func (p *Player) Invisible() bool {
	return p.invisible.Load()
}
Invisible checks if the Player is currently invisible.
package player
import (
	"fmt"
	"github.com/df-mc/dragonfly/server/block"
	blockAction "github.com/df-mc/dragonfly/server/block/action"
	"github.com/df-mc/dragonfly/server/block/cube"
	"github.com/df-mc/dragonfly/server/cmd"
	"github.com/df-mc/dragonfly/server/entity"
	"github.com/df-mc/dragonfly/server/entity/action"
	"github.com/df-mc/dragonfly/server/entity/damage"
	"github.com/df-mc/dragonfly/server/entity/effect"
	"github.com/df-mc/dragonfly/server/entity/healing"
	"github.com/df-mc/dragonfly/server/entity/physics"
	"github.com/df-mc/dragonfly/server/event"
	"github.com/df-mc/dragonfly/server/item"
	"github.com/df-mc/dragonfly/server/item/armour"
	"github.com/df-mc/dragonfly/server/item/enchantment"
	"github.com/df-mc/dragonfly/server/item/inventory"
	"github.com/df-mc/dragonfly/server/item/tool"
	"github.com/df-mc/dragonfly/server/player/bossbar"
	"github.com/df-mc/dragonfly/server/player/chat"
	"github.com/df-mc/dragonfly/server/player/form"
	"github.com/df-mc/dragonfly/server/player/scoreboard"
	"github.com/df-mc/dragonfly/server/player/skin"
	"github.com/df-mc/dragonfly/server/player/title"
	"github.com/df-mc/dragonfly/server/session"
	"github.com/df-mc/dragonfly/server/world"
	"github.com/df-mc/dragonfly/server/world/particle"
	"github.com/df-mc/dragonfly/server/world/sound"
	"github.com/go-gl/mathgl/mgl64"
	"github.com/google/uuid"
	"go.uber.org/atomic"
	"golang.org/x/text/language"
	"math"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"
)
type Player struct {
	name                                string
	uuid                                uuid.UUID
	xuid                                string
	locale                              language.Tag
	pos, vel                            atomic.Value
	nameTag                             atomic.String
	yaw, pitch, absorptionHealth, scale atomic.Float64
	gameModeMu sync.RWMutex
	gameMode   world.GameMode
	skinMu sync.RWMutex
	skin   skin.Skin
	sMutex sync.RWMutex
	s *session.Session
	hMutex sync.RWMutex
	h Handler
	inv, offHand *inventory.Inventory
	armour       *inventory.Armour
	heldSlot     *atomic.Uint32
	sneaking, sprinting, swimming, flying,
	invisible, immobile, onGround, usingItem atomic.Bool
	usingSince atomic.Int64
	fireTicks    atomic.Int64
	fallDistance atomic.Float64
	speed    atomic.Float64
	health   *entity.HealthManager
	effects  *entity.EffectManager
	immunity atomic.Value
	mc *entity.MovementComputer
	breaking          atomic.Bool
	breakingPos       atomic.Value
	lastBreakDuration time.Duration
	breakParticleCounter atomic.Uint32
	hunger *hungerManager
}
func New(name string, skin skin.Skin, pos mgl64.Vec3) *Player {
	p := &Player{}
	*p = Player{
		inv: inventory.New(36, func(slot int, item item.Stack) {
			if slot == int(p.heldSlot.Load()) {
				p.broadcastItems(slot, item)
			}
		}),
		uuid:     uuid.New(),
		offHand:  inventory.New(1, p.broadcastItems),
		armour:   inventory.NewArmour(p.broadcastArmour),
		hunger:   newHungerManager(),
		health:   entity.NewHealthManager(),
		effects:  entity.NewEffectManager(),
		gameMode: world.GameModeAdventure{},
		h:        NopHandler{},
		name:     name,
		skin:     skin,
		speed:    *atomic.NewFloat64(0.1),
		nameTag:  *atomic.NewString(name),
		heldSlot: atomic.NewUint32(0),
		locale:   language.BritishEnglish,
		scale:    *atomic.NewFloat64(1),
	}
	p.mc = &entity.MovementComputer{Gravity: 0.08, Drag: 0.02, DragBeforeGravity: true}
	p.pos.Store(pos)
	p.vel.Store(mgl64.Vec3{})
	p.immunity.Store(time.Now())
	p.breakingPos.Store(cube.Pos{})
	return p
}
func NewWithSession(name, xuid string, uuid uuid.UUID, skin skin.Skin, s *session.Session, pos mgl64.Vec3, data *Data) *Player {
	p := New(name, skin, pos)
	p.s, p.uuid, p.xuid, p.skin = s, uuid, xuid, skin
	p.inv, p.offHand, p.armour, p.heldSlot = s.HandleInventories()
	p.locale, _ = language.Parse(strings.Replace(s.ClientData().LanguageCode, "_", "-", 1))
	chat.Global.Subscribe(p)
	if data != nil {
		p.load(*data)
	}
	return p
}
func (p *Player) Name() string {
	return p.name
}
func (p *Player) UUID() uuid.UUID {
	return p.uuid
}
func (p *Player) XUID() string {
	return p.xuid
}
func (p *Player) Addr() net.Addr {
	if p.session() == session.Nop {
		return nil
	}
	return p.session().Addr()
}
func (p *Player) Skin() skin.Skin {
	p.skinMu.RLock()
	defer p.skinMu.RUnlock()
	return p.skin
}
func (p *Player) SetSkin(skin skin.Skin) {
	if p.Dead() {
		return
	}
	ctx := event.C()
	p.handler().HandleSkinChange(ctx, skin)
	ctx.Continue(func() {
		p.skinMu.Lock()
		p.skin = skin
		p.skinMu.Unlock()
		for _, v := range p.viewers() {
			v.ViewSkin(p)
		}
	})
	ctx.Stop(func() {
		p.session().ViewSkin(p)
	})
}
func (p *Player) Locale() language.Tag {
	return p.locale
}
func (p *Player) Handle(h Handler) {
	p.hMutex.Lock()
	defer p.hMutex.Unlock()
	if h == nil {
		h = NopHandler{}
	}
	p.h = h
}
func (p *Player) Message(a ...interface{}) {
	p.session().SendMessage(format(a))
}
func (p *Player) Messagef(f string, a ...interface{}) {
	msg := fmt.Sprintf(f, a...)
	p.session().SendMessage(msg)
}
func (p *Player) SendPopup(a ...interface{}) {
	p.session().SendPopup(format(a))
}
func (p *Player) SendTip(a ...interface{}) {
	p.session().SendTip(format(a))
}
func (p *Player) ResetFallDistance() {
	p.fallDistance.Store(0)
}
func (p *Player) FallDistance() float64 {
	return p.fallDistance.Load()
}
func (p *Player) SendTitle(t title.Title) {
	p.session().SetTitleDurations(t.FadeInDuration(), t.Duration(), t.FadeOutDuration())
	p.session().SendTitle(t.Text())
	if t.Subtitle() != "" {
		p.session().SendSubtitle(t.Subtitle())
	}
	if t.ActionText() != "" {
		p.session().SendActionBarMessage(t.ActionText())
	}
}
func (p *Player) SendScoreboard(scoreboard *scoreboard.Scoreboard) {
	p.session().SendScoreboard(scoreboard)
}
func (p *Player) RemoveScoreboard() {
	p.session().RemoveScoreboard()
}
func (p *Player) SendBossBar(bar bossbar.BossBar) {
	p.session().SendBossBar(bar.Text(), bar.HealthPercentage())
}
func (p *Player) RemoveBossBar() {
	p.session().RemoveBossBar()
}
func (p *Player) Chat(msg ...interface{}) {
	message := format(msg)
	ctx := event.C()
	p.handler().HandleChat(ctx, &message)
	ctx.Continue(func() {
		_, _ = fmt.Fprintf(chat.Global, "<%v> %v\n", p.name, message)
	})
}
func (p *Player) ExecuteCommand(commandLine string) {
	if p.Dead() {
		return
	}
	args := strings.Split(commandLine, " ")
	commandName := strings.TrimPrefix(args[0], "/")
	command, ok := cmd.ByAlias(commandName)
	if !ok {
		output := &cmd.Output{}
		output.Errorf("Unknown command '%v'", commandName)
		p.SendCommandOutput(output)
		return
	}
	ctx := event.C()
	p.handler().HandleCommandExecution(ctx, command, args[1:])
	ctx.Continue(func() {
		command.Execute(strings.TrimPrefix(strings.TrimPrefix(commandLine, "/"+commandName), " "), p)
	})
}
func (p *Player) Disconnect(msg ...interface{}) {
	p.session().Disconnect(format(msg))
	p.close()
}
func (p *Player) Transfer(address string) (err error) {
	addr, err := net.ResolveUDPAddr("udp", address)
	if err != nil {
		return err
	}
	ctx := event.C()
	p.handler().HandleTransfer(ctx, addr)
	ctx.Continue(func() {
		p.session().Transfer(addr.IP, addr.Port)
	})
	return
}
func (p *Player) SendCommandOutput(output *cmd.Output) {
	p.session().SendCommandOutput(output)
}
func (p *Player) SendForm(f form.Form) {
	p.session().SendForm(f)
}
func (p *Player) ShowCoordinates() {
	p.session().EnableCoordinates(true)
}
func (p *Player) HideCoordinates() {
	p.session().EnableCoordinates(false)
}
func (p *Player) EnableInstantRespawn() {
	p.session().EnableInstantRespawn(true)
}
func (p *Player) DisableInstantRespawn() {
	p.session().EnableInstantRespawn(false)
}
func (p *Player) SetNameTag(name string) {
	p.nameTag.Store(name)
	p.updateState()
}
func (p *Player) NameTag() string {
	return p.nameTag.Load()
}
func (p *Player) SetSpeed(speed float64) {
	p.speed.Store(speed)
	p.session().SendSpeed(speed)
}
func (p *Player) Speed() float64 {
	return p.speed.Load()
}
func (p *Player) Health() float64 {
	return p.health.Health()
}
func (p *Player) MaxHealth() float64 {
	return p.health.MaxHealth()
}
func (p *Player) SetMaxHealth(health float64) {
	p.health.SetMaxHealth(health)
	p.session().SendHealth(p.health)
}
func (p *Player) addHealth(health float64) {
	p.health.AddHealth(health)
	p.session().SendHealth(p.health)
}
func (p *Player) Heal(health float64, source healing.Source) {
	if p.Dead() || health < 0 || !p.GameMode().AllowsTakingDamage() {
		return
	}
	ctx := event.C()
	p.handler().HandleHeal(ctx, &health, source)
	ctx.Continue(func() {
		p.addHealth(health)
	})
}
func (p *Player) updateFallState(distanceThisTick float64) {
	fallDistance := p.fallDistance.Load()
	if p.OnGround() {
		if fallDistance > 0 {
			p.fall(fallDistance)
			p.ResetFallDistance()
		}
	} else if distanceThisTick < fallDistance {
		p.fallDistance.Sub(distanceThisTick)
	} else {
		p.ResetFallDistance()
	}
}
func (p *Player) fall(fallDistance float64) {
	w := p.World()
	pos := cube.PosFromVec3(p.Position())
	b := w.Block(pos)
	if len(b.Model().AABB(pos, w)) == 0 {
		pos = pos.Side(cube.FaceDown)
		b = w.Block(pos)
	}
	if h, ok := b.(block.EntityLander); ok {
		h.EntityLand(pos, w, p)
	}
	fallDamage := fallDistance - 3
	for _, e := range p.Effects() {
		if _, ok := e.Type().(effect.JumpBoost); ok {
			fallDamage -= float64(e.Level())
		}
	}
	if fallDamage < 0.5 {
		return
	}
	p.Hurt(math.Ceil(fallDamage), damage.SourceFall{})
}
func (p *Player) Hurt(dmg float64, source damage.Source) (float64, bool) {
	if p.Dead() || !p.GameMode().AllowsTakingDamage() {
		return 0, false
	}
	for _, e := range p.Effects() {
		if _, ok := e.Type().(effect.FireResistance); ok && (source == damage.SourceFire{} || source == damage.SourceFireTick{} || source == damage.SourceLava{}) {
			return 0, false
		}
	}
	var (
		ctx        = event.C()
		vulnerable = false
		n          = 0.0
	)
	p.handler().HandleHurt(ctx, &dmg, source)
	ctx.Continue(func() {
		vulnerable = true
		if dmg < 0 {
			return
		}
		if source.ReducedByArmour() {
			p.Exhaust(0.1)
		}
		finalDamage := p.FinalDamageFrom(dmg, source)
		n = finalDamage
		a := p.absorption()
		if a > 0 && (effect.Absorption{}).Absorbs(source) {
			if finalDamage > a {
				finalDamage -= a
				p.SetAbsorption(0)
				p.effects.Remove(effect.Absorption{}, p)
			} else {
				p.SetAbsorption(a - finalDamage)
				finalDamage = 0
			}
		}
		if src, ok := source.(damage.SourceEntityAttack); ok {
			var d int
			for i, it := range p.armour.Slots() {
				if t, ok := it.Enchantment(enchantment.Thorns{}); ok {
					if rand.Float64() < float64(t.Level())*0.15 {
						_ = p.armour.Inv().SetItem(i, p.damageItem(it, 3))
						if t.Level() > 10 {
							d += t.Level() - 10
							continue
						}
						d += 1 + rand.Intn(4)
					} else {
						_ = p.armour.Inv().SetItem(i, p.damageItem(it, 1))
					}
				}
			}
			if l, ok := src.Attacker.(entity.Living); ok && d > 0 {
				l.Hurt(float64(d), damage.SourceCustom{})
			}
		}
		p.addHealth(-finalDamage)
		for _, viewer := range p.viewers() {
			viewer.ViewEntityAction(p, action.Hurt{})
		}
		p.immunity.Store(time.Now().Add(time.Second / 2))
		if p.Dead() {
			p.kill(source)
		}
	})
	return n, vulnerable
}
func (p *Player) FinalDamageFrom(dmg float64, src damage.Source) float64 {
	if src.ReducedByArmour() {
		defencePoints, damageToArmour := 0.0, int(dmg/4)
		if damageToArmour == 0 {
			damageToArmour++
		}
		for i, it := range p.armour.Slots() {
			if a, ok := it.Item().(armour.Armour); ok {
				defencePoints += a.DefencePoints()
				if _, ok := it.Item().(item.Durable); ok {
					_ = p.armour.Inv().SetItem(i, p.damageItem(it, damageToArmour))
				}
			}
		}
		dmg -= dmg * 0.04 * defencePoints
	}
	for _, e := range p.Effects() {
		if resistance, ok := e.Type().(effect.Resistance); ok {
			dmg *= resistance.Multiplier(src, e.Level())
		}
	}
	if entityAttack, ok := src.(damage.SourceEntityAttack); ok {
		if carrier, ok := entityAttack.Attacker.(item.Carrier); ok {
			held, _ := carrier.HeldItems()
			if e, ok := held.Enchantment(enchantment.Sharpness{}); ok {
				dmg += (enchantment.Sharpness{}).Addend(e.Level())
			}
		}
	}
	for _, it := range p.armour.Items() {
		if p, ok := it.Enchantment(enchantment.Protection{}); ok {
			dmg -= (enchantment.Protection{}).Subtrahend(p.Level())
		}
	}
	if f, ok := p.Armour().Boots().Enchantment(enchantment.FeatherFalling{}); ok && (src == damage.SourceFall{}) {
		dmg *= (enchantment.FeatherFalling{}).Multiplier(f.Level())
	}
	if dmg < 0 {
		dmg = 0
	}
	return dmg
}
func (p *Player) SetAbsorption(health float64) {
	if health < 0 {
		return
	}
	p.absorptionHealth.Store(health)
	p.session().SendAbsorption(health)
}
func (p *Player) absorption() float64 {
	return p.absorptionHealth.Load()
}
func (p *Player) KnockBack(src mgl64.Vec3, force, height float64) {
	if p.Dead() || !p.GameMode().AllowsTakingDamage() {
		return
	}
	velocity := p.Position().Sub(src)
	velocity[1] = 0
	velocity = velocity.Normalize().Mul(force)
	velocity[1] = height
	resistance := 0.0
	for _, i := range p.armour.Items() {
		if a, ok := i.Item().(armour.Armour); ok {
			resistance += a.KnockBackResistance()
		}
	}
	p.SetVelocity(velocity.Mul(1 - resistance))
}
func (p *Player) AttackImmune() bool {
	return p.immunity.Load().(time.Time).After(time.Now())
}
func (p *Player) Food() int {
	return p.hunger.Food()
}
func (p *Player) SetFood(level int) {
	p.hunger.SetFood(level)
	p.sendFood()
}
func (p *Player) AddFood(points int) {
	p.hunger.AddFood(points)
	p.sendFood()
}
func (p *Player) Saturate(food int, saturation float64) {
	p.hunger.saturate(food, saturation)
	p.sendFood()
}
func (p *Player) sendFood() {
	p.hunger.mu.RLock()
	defer p.hunger.mu.RUnlock()
	p.session().SendFood(p.hunger.foodLevel, p.hunger.saturationLevel, p.hunger.exhaustionLevel)
}
func (p *Player) AddEffect(e effect.Effect) {
	p.session().SendEffect(p.effects.Add(e, p))
	p.updateState()
}
func (p *Player) RemoveEffect(e effect.Type) {
	p.effects.Remove(e, p)
	p.session().SendEffectRemoval(e)
	p.updateState()
}
func (p *Player) Effects() []effect.Effect {
	return p.effects.Effects()
}
func (*Player) BeaconAffected() bool {
	return true
}
func (p *Player) Exhaust(points float64) {
	if !p.GameMode().AllowsTakingDamage() {
		return
	}
	before := p.hunger.Food()
	if !p.World().Difficulty().FoodRegenerates() {
		p.hunger.exhaust(points)
	}
	after := p.hunger.Food()
	if before != after {
		p.hunger.SetFood(before)
		ctx := event.C()
		p.handler().HandleFoodLoss(ctx, before, after)
		ctx.Continue(func() {
			p.hunger.SetFood(after)
			if before >= 7 && after <= 6 {
				p.StopSprinting()
			}
		})
	}
	p.sendFood()
}
func (p *Player) Dead() bool {
	return p.Health() <= 0
}
func (p *Player) kill(src damage.Source) {
	for _, viewer := range p.viewers() {
		viewer.ViewEntityAction(p, action.Death{})
	}
	p.addHealth(-p.MaxHealth())
	p.StopSneaking()
	p.StopSprinting()
	p.inv.Clear()
	p.armour.Clear()
	p.offHand.Clear()
	for _, e := range p.Effects() {
		p.RemoveEffect(e.Type())
	}
	p.handler().HandleDeath(src)
	time.AfterFunc(time.Millisecond*1100, func() {
		if p.session() == session.Nop {
			_ = p.Close()
			return
		}
		if p.Dead() {
			p.SetInvisible()
			p.pos.Store(p.World().Spawn().Vec3())
		}
	})
}
func (p *Player) Respawn() {
	if !p.Dead() || p.World() == nil || p.session() == session.Nop {
		return
	}
	pos := p.World().Spawn().Vec3Middle()
	p.handler().HandleRespawn(&pos)
	p.addHealth(p.MaxHealth())
	p.hunger.Reset()
	p.sendFood()
	p.Extinguish()
	p.World().AddEntity(p)
	p.SetVisible()
	p.Teleport(pos)
	p.session().SendRespawn()
}
func (p *Player) StartSprinting() {
	if !p.hunger.canSprint() && p.GameMode().AllowsTakingDamage() {
		return
	}
	ctx := event.C()
	p.handler().HandleToggleSprint(ctx, true)
	ctx.Continue(func() {
		if !p.sprinting.CAS(false, true) {
			return
		}
		p.StopSneaking()
		p.SetSpeed(p.Speed() * 1.3)
		p.updateState()
	})
}
func (p *Player) Sprinting() bool {
	return p.sprinting.Load()
}
func (p *Player) StopSprinting() {
	ctx := event.C()
	p.handler().HandleToggleSprint(ctx, false)
	ctx.Continue(func() {
		if !p.sprinting.CAS(true, false) {
			return
		}
		p.SetSpeed(p.Speed() / 1.3)
		p.updateState()
	})
}
func (p *Player) StartSneaking() {
	ctx := event.C()
	p.handler().HandleToggleSneak(ctx, true)
	ctx.Continue(func() {
		if !p.sneaking.CAS(false, true) {
			return
		}
		p.StopSprinting()
		p.updateState()
	})
}
func (p *Player) Sneaking() bool {
	return p.sneaking.Load()
}
func (p *Player) StopSneaking() {
	ctx := event.C()
	p.handler().HandleToggleSneak(ctx, false)
	ctx.Continue(func() {
		if !p.sneaking.CAS(true, false) {
			return
		}
		p.updateState()
	})
}
func (p *Player) StartSwimming() {
	if !p.swimming.CAS(false, true) {
		return
	}
	p.StopSneaking()
	p.updateState()
}
func (p *Player) Swimming() bool {
	return p.swimming.Load()
}
func (p *Player) StopSwimming() {
	if !p.swimming.CAS(true, false) {
		return
	}
	p.updateState()
}
func (p *Player) StartFlying() {
	if !p.GameMode().AllowsFlying() || !p.flying.CAS(false, true) {
		return
	}
	p.session().SendGameMode(p.GameMode())
}
func (p *Player) Flying() bool {
	return p.flying.Load()
}
func (p *Player) StopFlying() {
	if !p.flying.CAS(true, false) {
		return
	}
	p.session().SendGameMode(p.GameMode())
}
func (p *Player) SetInvisible() {
	if !p.invisible.CAS(false, true) {
		return
	}
	p.updateState()
}
func (p *Player) SetVisible() {
	if !p.GameMode().Visible() {
		return
	}
	for _, eff := range p.Effects() {
		if _, ok := eff.Type().(effect.Invisibility); ok {
			return
		}
	}
	if !p.invisible.CAS(true, false) {
		return
	}
	p.updateState()
}