Skip to content

Commit

Permalink
Lo and behold: It compiles!
Browse files Browse the repository at this point in the history
Still need to deal with commands and probably everything is broken, but it's a start.
  • Loading branch information
Sandertv committed Nov 18, 2024
1 parent 2b2a7e1 commit 46a72d6
Show file tree
Hide file tree
Showing 26 changed files with 142 additions and 127 deletions.
4 changes: 0 additions & 4 deletions server/cmd/source.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package cmd

import "github.com/df-mc/dragonfly/server/world"

// Source represents a source of a command execution. Commands may limit the sources that can run them by
// implementing the Allower interface.
// Source implements Target. A Source must always be able to target itself.
Expand All @@ -11,6 +9,4 @@ type Source interface {
// kind of source it is.
// SendCommandOutput is called by a Command automatically after being run.
SendCommandOutput(o *Output)
// World returns the world that the Source is in.
World() *world.World
}
4 changes: 2 additions & 2 deletions server/entity/area_effect_cloud_behaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (a *AreaEffectCloudBehaviour) Tick(e *Ent, tx *world.Tx) *Movement {
func (a *AreaEffectCloudBehaviour) filter(seq iter.Seq[world.Entity]) iter.Seq[world.Entity] {
return func(yield func(world.Entity) bool) {
for e := range seq {
_, target := a.targets[e.Handle()]
_, target := a.targets[e.H()]
_, living := e.(Living)
if !living || target {
continue
Expand Down Expand Up @@ -143,7 +143,7 @@ func (a *AreaEffectCloudBehaviour) applyEffects(pos mgl64.Vec3, ent *Ent, entiti
l.AddEffect(eff)
}

a.targets[e.Handle()] = ent.Age() + a.conf.ReapplicationDelay
a.targets[e.H()] = ent.Age() + a.conf.ReapplicationDelay
a.subtractUseDuration()
a.subtractUseRadius()

Expand Down
2 changes: 1 addition & 1 deletion server/entity/arrow.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewTippedArrowWithDamage(opts world.EntitySpawnOpts, damage float64, owner
conf := arrowConf
conf.Damage = damage
conf.Potion = tip
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(ArrowType{}, conf)
}

Expand Down
2 changes: 1 addition & 1 deletion server/entity/bottle_of_enchanting.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// NewBottleOfEnchanting ...
func NewBottleOfEnchanting(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle {
conf := bottleOfEnchantingConf
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(BottleOfEnchantingType{}, conf)
}

Expand Down
2 changes: 1 addition & 1 deletion server/entity/egg.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// to spawn chicks.
func NewEgg(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle {
conf := eggConf
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(EggType{}, conf)
}

Expand Down
2 changes: 1 addition & 1 deletion server/entity/ender_pearl.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// blue item used to teleport.
func NewEnderPearl(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle {
conf := enderPearlConf
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(EnderPearlType{}, conf)
}

Expand Down
5 changes: 2 additions & 3 deletions server/entity/ent.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ type Ent struct {
data *world.EntityData
}

func (e *Ent) Handle() *world.EntityHandle {
// TODO: Move this over to world.EntityHandle.
return nil
func (e *Ent) H() *world.EntityHandle {
return e.handle
}

func (e *Ent) Behaviour() Behaviour {
Expand Down
2 changes: 1 addition & 1 deletion server/entity/experience_orb_behaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (exp *ExperienceOrbBehaviour) findTarget(tx *world.Tx, pos mgl64.Vec3) {
exp.target = nil
for o := range tx.EntitiesWithin(followBox.Translate(pos)) {
if _, ok := o.(experienceCollector); ok {
exp.target = o.Handle()
exp.target = o.H()
break
}
}
Expand Down
4 changes: 2 additions & 2 deletions server/entity/firework.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ func NewFireworkAttached(opts world.EntitySpawnOpts, firework item.Firework, own
conf := fireworkConf
conf.ExistenceDuration = firework.RandomisedDuration()
conf.Attached = attached
conf.Owner = owner.Handle()
return world.NewEntity(FireworkType{}, conf)
conf.Owner = owner.H()
return opts.New(FireworkType{}, conf)
}

var fireworkConf = FireworkBehaviourConfig{
Expand Down
2 changes: 1 addition & 1 deletion server/entity/lingering_potion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func NewLingeringPotion(opts world.EntitySpawnOpts, t potion.Potion, owner world
conf.Potion = t
conf.Particle = particle.Splash{Colour: colour}
conf.Hit = potionSplash(0.25, t, true)
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(LingeringPotionType{}, conf)
}

Expand Down
2 changes: 1 addition & 1 deletion server/entity/projectile.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ func (lt *ProjectileBehaviour) ignores(e *Ent) trace.EntityFilter {
for other := range seq {
g, ok := other.(interface{ GameMode() world.GameMode })
_, living := other.(Living)
if (ok && !g.GameMode().HasCollision()) || e == other || !living || (e.data.Age < time.Second/4 && lt.conf.Owner == other.Handle()) {
if (ok && !g.GameMode().HasCollision()) || e == other || !living || (e.data.Age < time.Second/4 && lt.conf.Owner == other.H()) {
continue
}
if !yield(other) {
Expand Down
2 changes: 1 addition & 1 deletion server/entity/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var conf = world.EntityRegistryConfig{
},
Arrow: func(opts world.EntitySpawnOpts, damage float64, owner world.Entity, critical, disallowPickup, obtainArrowOnPickup bool, punchLevel int, tip any) *world.EntityHandle {
conf := arrowConf
conf.Damage, conf.Potion, conf.Owner = damage, tip.(potion.Potion), owner.Handle()
conf.Damage, conf.Potion, conf.Owner = damage, tip.(potion.Potion), owner.H()
conf.KnockBackForceAddend = float64(punchLevel) * (enchantment.Punch{}).KnockBackMultiplier()
conf.DisablePickup = disallowPickup
if obtainArrowOnPickup {
Expand Down
2 changes: 1 addition & 1 deletion server/entity/snowball.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// NewSnowball creates a snowball entity at a position with an owner entity.
func NewSnowball(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle {
conf := snowballConf
conf.Owner = owner.Handle()
conf.Owner = owner.H()
return opts.New(SnowballType{}, conf)
}

Expand Down
2 changes: 1 addition & 1 deletion server/entity/splash_potion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func NewSplashPotion(opts world.EntitySpawnOpts, t potion.Potion, owner world.En
conf.Potion = t
conf.Particle = particle.Splash{Colour: colour}
conf.Hit = potionSplash(1, t, false)
conf.Owner = owner.Handle()
conf.Owner = owner.H()

return opts.New(SplashPotionType{}, conf)
}
Expand Down
2 changes: 1 addition & 1 deletion server/item/inventory/armour.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func (a *Armour) Inventory() *Inventory {

// Handle assigns a Handler to an Armour inventory so that its methods are called for the respective events. Nil may be
// passed to set the default NopHandler.
// Handle is the equivalent of calling (*Armour).Inventory().Handle.
// Handle is the equivalent of calling (*Armour).Inventory().H.
func (a *Armour) Handle(h Handler) {
a.inv.Handle(h)
}
Expand Down
7 changes: 7 additions & 0 deletions server/item/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func (inv *Inventory) Clone(f SlotFunc) *Inventory {
return &Inventory{h: NopHandler{}, slots: inv.Slots(), f: f, canAdd: func(s item.Stack, slot int) bool { return true }}
}

// SlotFunc changes the function called when a slot in the inventory is changed.
func (inv *Inventory) SlotFunc(f SlotFunc) {
inv.mu.Lock()
defer inv.mu.Unlock()
inv.f = f
}

// Item attempts to obtain an item from a specific slot in the inventory. If an item was present in that slot,
// the item is returned and the error is nil. If no item was present in the slot, a Stack with air as its item
// and a count of 0 is returned. Stack.Empty() may be called to check if this is the case.
Expand Down
91 changes: 56 additions & 35 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"net"
"strings"
"sync"
"time"

"github.com/df-mc/dragonfly/server/block"
Expand Down Expand Up @@ -47,9 +48,9 @@ type playerData struct {
s *session.Session
h Handler

inv, offHand, enderChest *inventory.Inventory
armour *inventory.Armour
heldSlot *uint32
inv, offHand, enderChest, ui *inventory.Inventory
armour *inventory.Armour
heldSlot *uint32

sneaking, sprinting, swimming, gliding, flying,
invisible, immobile, onGround, usingItem bool
Expand Down Expand Up @@ -89,6 +90,8 @@ type playerData struct {
breakParticleCounter uint32

hunger *hungerManager

once sync.Once
}

// Player is an implementation of a player entity. It has methods that implement the behaviour that players
Expand All @@ -100,29 +103,15 @@ type Player struct {
*playerData
}

// NewWithSession returns a new player for a network session, so that the network session can control the
// player.
// A set of additional fields must be provided to initialise the player with the client's data, such as the
// name and the skin of the player. You can either pass on player data you want to load or
// you can leave the data as nil to use default data.
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.Store(s)
p.skin.Store(&skin)
p.uuid, p.xuid = uuid, xuid
p.inv, p.offHand, p.enderChest, p.armour, p.heldSlot = s.HandleInventories()
p.locale, _ = language.Parse(strings.Replace(s.ClientData().LanguageCode, "_", "-", 1))
if data != nil {
p.load(*data)
}
return p
}

// Type returns the world.EntityType for the Player.
func (p *Player) Type() world.EntityType {
return Type{}
}

func (p *Player) H() *world.EntityHandle {
return p.handle
}

// Name returns the username of the player. If the player is controlled by a client, it is the username of
// the client. (Typically the XBOX Live name)
func (p *Player) Name() string {
Expand Down Expand Up @@ -213,7 +202,7 @@ func (p *Player) Handle(h Handler) {
if h == nil {
h = NopHandler{}
}
p.h.Store(&h)
p.h = h
}

// Message sends a formatted message to the player. The message is formatted following the rules of
Expand Down Expand Up @@ -839,7 +828,7 @@ func (p *Player) dropItems() {
p.experience.Reset()
p.session().SendExperience(p.experience)

p.session().EmptyUIInventory()
p.MoveItemsToInventory()
for _, it := range append(p.inv.Clear(), append(p.armour.Clear(), p.offHand.Clear()...)...) {
if _, ok := it.Enchantment(enchantment.CurseOfVanishing{}); ok {
continue
Expand All @@ -849,9 +838,31 @@ func (p *Player) dropItems() {
}
}

// Respawn spawns the player after it dies, so that its health is replenished and it is spawned in the world
// again. Nothing will happen if the player does not have a session connected to it.
func (p *Player) Respawn() {
// MoveItemsToInventory moves items kept in 'temporary' slots, such as the
// crafting grid of slots in an enchantment table, to the player's inventory.
// If no space is left for these items, the leftover items are dropped.
func (p *Player) MoveItemsToInventory() {
for _, i := range p.ui.Clear() {
if n, err := p.inv.AddItem(i); err != nil {
// We couldn't add the item to the main inventory (probably because
// it was full), so we drop it instead.
p.Drop(i.Grow(i.Count() - n))
}
}
}

// Respawn spawns the player after it dies, so that its health is replenished,
// and it is spawned in the world again. Nothing will happen if the player does
// not have a session connected to it.
// Calling Respawn may lead to the player being removed from its world and being
// added to a new world. This means that p cannot be assumed to be valid after
// a call to Respawn.
func (p *Player) Respawn() *world.EntityHandle {
p.respawn(nil)
return p.handle
}

func (p *Player) respawn(f func(p *Player)) {
if !p.Dead() || p.session() == session.Nop {
return
}
Expand All @@ -870,10 +881,13 @@ func (p *Player) Respawn() {

handle := p.tx.RemoveEntity(p)
w.Exec(func(tx *world.Tx) {
p = tx.AddEntity(handle).(*Player)
p.Teleport(pos)
p.session().SendRespawn(pos, p)
p.SetVisible()
np := tx.AddEntity(handle).(*Player)
np.Teleport(pos)
np.session().SendRespawn(pos, p)
np.SetVisible()
if f != nil {
f(np)
}
})
}

Expand Down Expand Up @@ -1309,7 +1323,7 @@ func (p *Player) ReleaseItem() {
p.usingItem = false
ctx := p.useContext()
i, _ := p.HeldItems()
i.Item().(item.Releasable).Release(p, p.useDuration(), nil, ctx)
i.Item().(item.Releasable).Release(p, p.tx, ctx, p.useDuration())

p.handleUseContext(ctx)
p.updateState()
Expand Down Expand Up @@ -1414,7 +1428,7 @@ func (p *Player) UseItemOnBlock(pos cube.Pos, face cube.Face, clickPos mgl64.Vec
// The block clicked was either not replaceable, or not replaceable using the block passed.
replacedPos = pos.Side(face)
}
if replaceable, ok := p.tx.Block(replacedPos).(block.Replaceable); !ok || !replaceable.ReplaceableBy(ib) || replacedPos.OutOfBounds(w.Range()) {
if replaceable, ok := p.tx.Block(replacedPos).(block.Replaceable); !ok || !replaceable.ReplaceableBy(ib) || replacedPos.OutOfBounds(p.tx.Range()) {
return
}
if !p.placeBlock(replacedPos, ib, false) || p.GameMode().CreativeInventory() {
Expand All @@ -1441,7 +1455,7 @@ func (p *Player) UseItemOnEntity(e world.Entity) bool {
return true
}
useCtx := p.useContext()
if !usable.UseOnEntity(e, p.tx.World(), p, useCtx) {
if !usable.UseOnEntity(e, p.tx, p, useCtx) {
return true
}
p.SwingArm()
Expand Down Expand Up @@ -2223,7 +2237,7 @@ func (p *Player) Tick(_ *world.World, current int64) {
}

if p.session() == session.Nop && !p.Immobile() {
m := p.mc.TickMovement(p, p.Position(), p.Velocity(), p.Rotation())
m := p.mc.TickMovement(p, p.Position(), p.Velocity(), p.Rotation(), p.tx)
m.Send()

p.data.Vel = m.Velocity()
Expand Down Expand Up @@ -2706,8 +2720,15 @@ func (p *Player) close(msg string) {
// If the player is being disconnected while they are dead, we respawn the player
// so that the player logic works correctly the next time they join.
if p.Dead() && p.session() != nil {
p.Respawn()
p.respawn(func(np *Player) {
np.quit(msg)
})
return
}
p.quit(msg)
}

func (p *Player) quit(msg string) {
p.h.HandleQuit()
p.h = NopHandler{}

Expand Down
11 changes: 5 additions & 6 deletions server/player/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (conf Config) Apply(data *world.EntityData) {
}
data.Name, data.Pos = conf.Name, conf.Pos
data.Data = &playerData{
ui: inventory.New(54, nil),
inv: inventory.New(36, nil),
enderChest: inventory.New(27, nil),
offHand: inventory.New(1, nil),
Expand Down Expand Up @@ -79,18 +80,16 @@ func (t Type) Open(tx *world.Tx, handle *world.EntityHandle, data *world.EntityD
playerData: pd,
}

// TODO: Make sure inventories don't get recreated everytime.
if pd.s != nil {
pd.inv, pd.offHand, pd.enderChest, pd.armour, pd.heldSlot = pd.s.HandleInventories(tx, p)
pd.s.HandleInventories(tx, p, pd.inv, pd.offHand, pd.enderChest, pd.ui, pd.armour, pd.heldSlot)
} else {
pd.inv = inventory.New(36, func(slot int, before, after item.Stack) {
pd.inv.SlotFunc(func(slot int, before, after item.Stack) {
if slot == int(*p.heldSlot) {
p.broadcastItems(slot, before, after)
}
})
pd.enderChest = inventory.New(27, nil)
pd.offHand = inventory.New(1, p.broadcastItems)
pd.armour = inventory.NewArmour(p.broadcastArmour)
pd.offHand.SlotFunc(p.broadcastItems)
pd.armour.Inventory().SlotFunc(p.broadcastArmour)
}

return p
Expand Down
Loading

0 comments on commit 46a72d6

Please sign in to comment.