From 45fdd5d21e6bff37befb46cf437d92008f1412f8 Mon Sep 17 00:00:00 2001 From: Sandertv Date: Thu, 9 Jan 2025 20:14:19 +0100 Subject: [PATCH] world/entity.go: EntityData: Unexport pos and rot. --- server/entity/ent.go | 12 ++--- server/entity/firework_behaviour.go | 13 ++++-- server/entity/passive.go | 7 +-- server/entity/projectile.go | 5 +- server/player/conf.go | 1 - server/player/player.go | 31 ++++--------- server/server.go | 8 +++- server/world/entity.go | 72 ++++++++++++++++++----------- server/world/world.go | 4 +- 9 files changed, 84 insertions(+), 69 deletions(-) diff --git a/server/entity/ent.go b/server/entity/ent.go index 13774cf8a..d6ed48022 100644 --- a/server/entity/ent.go +++ b/server/entity/ent.go @@ -51,24 +51,24 @@ func (e *Ent) Explode(src mgl64.Vec3, impact float64, conf block.ExplosionConfig // Position returns the current position of the entity. func (e *Ent) Position() mgl64.Vec3 { - return e.data.Pos + return e.data.Position() } // Velocity returns the current velocity of the entity. The values in the Vec3 returned represent the speed on // that axis in blocks/tick. func (e *Ent) Velocity() mgl64.Vec3 { - return e.data.Vel + return e.data.Velocity() } // SetVelocity sets the velocity of the entity. The values in the Vec3 passed represent the speed on // that axis in blocks/tick. func (e *Ent) SetVelocity(v mgl64.Vec3) { - e.data.Vel = v + e.data.SetVelocity(e, e.tx, v) } // Rotation returns the rotation of the entity. func (e *Ent) Rotation() cube.Rotation { - return e.data.Rot + return e.data.Rotation() } // Age returns the total time lived of this entity. It increases by @@ -89,7 +89,7 @@ func (e *Ent) SetOnFire(duration time.Duration) { e.data.FireDuration = duration if stateChanged { - for _, v := range e.tx.Viewers(e.data.Pos) { + for _, v := range e.tx.Viewers(e.data.Position()) { v.ViewEntityState(e) } } @@ -118,7 +118,7 @@ func (e *Ent) SetNameTag(s string) { // Tick ticks Ent, progressing its lifetime and closing the entity if it is // in the void. func (e *Ent) Tick(tx *world.Tx, current int64) { - y := e.data.Pos[1] + y := e.data.Position()[1] if y < float64(tx.Range()[0]) && current%10 == 0 { _ = e.Close() return diff --git a/server/entity/firework_behaviour.go b/server/entity/firework_behaviour.go index ae424fe8a..3a556acc8 100644 --- a/server/entity/firework_behaviour.go +++ b/server/entity/firework_behaviour.go @@ -85,17 +85,20 @@ func (f *FireworkBehaviour) tick(e *Ent, tx *world.Tx) { ownerVel = o.Velocity() } + vel := e.data.Velocity() if f.conf.Attached && ok { dV := owner.Rotation().Vec3() // The client will propel itself to match the firework's velocity since // we set the appropriate metadata. - e.data.Pos = owner.Position() - e.data.Vel = e.data.Vel.Add(ownerVel.Add(dV.Mul(0.1).Add(dV.Mul(1.5).Sub(ownerVel).Mul(0.5)))) + e.data.Move(e, tx, owner.Position(), e.data.Rotation(), false) + e.data.SetVelocity(e, tx, vel.Add(ownerVel.Add(dV.Mul(0.1).Add(dV.Mul(1.5).Sub(ownerVel).Mul(0.5))))) } else { - e.data.Vel[0] *= f.conf.SidewaysVelocityMultiplier - e.data.Vel[1] += f.conf.UpwardsAcceleration - e.data.Vel[2] *= f.conf.SidewaysVelocityMultiplier + e.data.SetVelocity(e, tx, mgl64.Vec3{ + vel[0] * f.conf.SidewaysVelocityMultiplier, + vel[1] * f.conf.UpwardsAcceleration, + vel[2] * f.conf.SidewaysVelocityMultiplier, + }) } } diff --git a/server/entity/passive.go b/server/entity/passive.go index d1d8b500a..7dab7d6a4 100644 --- a/server/entity/passive.go +++ b/server/entity/passive.go @@ -58,7 +58,7 @@ type PassiveBehaviour struct { // Explode adds velocity to a passive entity to blast it away from the // explosion's source. func (p *PassiveBehaviour) Explode(e *Ent, src mgl64.Vec3, impact float64, _ block.ExplosionConfig) { - e.data.Vel = e.data.Vel.Add(e.data.Pos.Sub(src).Normalize().Mul(impact)) + e.data.SetVelocity(e, e.tx, e.data.Velocity().Add(e.data.Position().Sub(src).Normalize().Mul(impact))) } // Fuse returns the leftover time until PassiveBehaviourConfig.Expire is called, @@ -78,8 +78,9 @@ func (p *PassiveBehaviour) Tick(e *Ent, tx *world.Tx) *Movement { return nil } - m := p.mc.TickMovement(e, e.data.Pos, e.data.Vel, e.data.Rot, tx) - e.data.Pos, e.data.Vel = m.pos, m.vel + m := p.mc.TickMovement(e, e.data.Position(), e.data.Velocity(), e.data.Rotation(), tx) + e.data.Move(e, tx, m.pos, m.rot, m.onGround) + e.data.SetVelocity(e, tx, m.vel) p.fallDistance = math.Max(p.fallDistance-m.dvel[1], 0) p.fuse = p.conf.ExistenceDuration - e.Age() diff --git a/server/entity/projectile.go b/server/entity/projectile.go index c2323d3b5..cd0e328a5 100644 --- a/server/entity/projectile.go +++ b/server/entity/projectile.go @@ -118,7 +118,7 @@ func (lt *ProjectileBehaviour) Owner() *world.EntityHandle { // Explode adds velocity to a projectile to blast it away from the explosion's // source. func (lt *ProjectileBehaviour) Explode(e *Ent, src mgl64.Vec3, impact float64, _ block.ExplosionConfig) { - e.data.Vel = e.Velocity().Add(e.Position().Sub(src).Normalize().Mul(impact)) + e.data.SetVelocity(e, e.tx, e.Velocity().Add(e.Position().Sub(src).Normalize().Mul(impact))) } // Potion returns the potion.Potion that is applied to an entity if hit by the @@ -150,7 +150,8 @@ func (lt *ProjectileBehaviour) Tick(e *Ent, tx *world.Tx) *Movement { } vel := e.Velocity() m, result := lt.tickMovement(e, tx) - e.data.Pos, e.data.Vel = m.pos, m.vel + e.data.Move(e, tx, m.pos, m.rot, m.onGround) + e.data.SetVelocity(e, tx, m.vel) lt.collisionPos, lt.collided, lt.ageCollided = cube.Pos{}, false, 0 diff --git a/server/player/conf.go b/server/player/conf.go index ed9c1f412..1e4423a5e 100644 --- a/server/player/conf.go +++ b/server/player/conf.go @@ -52,7 +52,6 @@ type Config struct { func (cfg Config) Apply(data *world.EntityData) { conf := fillDefaults(cfg) - data.Name, data.Pos, data.Rot = conf.Name, conf.Position, conf.Rotation slot := uint32(conf.HeldSlot) pdata := &playerData{ xuid: conf.XUID, diff --git a/server/player/player.go b/server/player/player.go index 9e3ad9526..ce95b303a 100644 --- a/server/player/player.go +++ b/server/player/player.go @@ -861,7 +861,7 @@ func finishDying(_ *world.Tx, e world.Entity) { // 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.data.Move(p, p.tx, p.tx.World().Spawn().Vec3(), p.Rotation(), p.onGround) } } @@ -2032,11 +2032,7 @@ func (p *Player) Teleport(pos mgl64.Vec3) { // teleport teleports the player to a target position in the world. It does not call the Handler of the // player. func (p *Player) teleport(pos mgl64.Vec3) { - for _, v := range p.viewers() { - v.ViewEntityTeleport(p, pos) - } - p.data.Pos = pos - p.data.Vel = mgl64.Vec3{} + p.data.Teleport(p, p.tx, pos) p.ResetFallDistance() } @@ -2068,12 +2064,7 @@ func (p *Player) Move(deltaPos mgl64.Vec3, deltaYaw, deltaPitch float64) { } return } - for _, v := range p.viewers() { - v.ViewEntityMovement(p, res, resRot, p.OnGround()) - } - - p.data.Pos = res - p.data.Rot = resRot + p.data.Move(p, p.tx, res, resRot, p.OnGround()) if deltaPos.Len() <= 3 { // Only update velocity if the player is not moving too fast to prevent potential OOMs. p.data.Vel = deltaPos @@ -2115,31 +2106,25 @@ func (p *Player) Move(deltaPos mgl64.Vec3, deltaYaw, deltaPitch float64) { // Position returns the current position of the player. It may be changed as the player moves or is moved // around the world. func (p *Player) Position() mgl64.Vec3 { - return p.data.Pos + return p.data.Position() } // Velocity returns the players current velocity. If there is an attached session, this will be empty. func (p *Player) Velocity() mgl64.Vec3 { - return p.data.Vel + return p.data.Velocity() } // SetVelocity updates the player's velocity. If there is an attached session, this will just send // the velocity to the player session for the player to update. func (p *Player) SetVelocity(velocity mgl64.Vec3) { - if p.session() == session.Nop { - p.data.Vel = velocity - return - } - for _, v := range p.viewers() { - v.ViewEntityVelocity(p, velocity) - } + p.data.SetVelocity(p, p.tx, velocity) } // Rotation returns the yaw and pitch of the player in degrees. Yaw is horizontal rotation (rotation around the // vertical axis, 0 when facing forward), pitch is vertical rotation (rotation around the horizontal axis, also 0 // when facing forward). func (p *Player) Rotation() cube.Rotation { - return p.data.Rot + return p.data.Rotation() } // Collect makes the player collect the item stack passed, adding it to the inventory. The amount of items that could @@ -2352,7 +2337,7 @@ func (p *Player) Tick(tx *world.Tx, current int64) { } } - p.checkBlockCollisions(p.data.Vel) + p.checkBlockCollisions(p.data.Velocity()) p.onGround = p.checkOnGround() p.effects.Tick(p, p.tx) diff --git a/server/server.go b/server/server.go index 678aacebf..4a5d7c92a 100644 --- a/server/server.go +++ b/server/server.go @@ -545,7 +545,13 @@ func (srv *Server) createPlayer(id uuid.UUID, conn session.Conn, conf player.Con conf.Skin = srv.parseSkin(conn.ClientData()) conf.Session = s - handle := world.EntitySpawnOpts{Position: conf.Position, ID: id}.New(player.Type, conf) + handle := world.EntitySpawnOpts{ + NameTag: conf.Name, + Position: conf.Position, + Rotation: conf.Rotation, + Velocity: conf.Velocity, + ID: id, + }.New(player.Type, conf) s.SetHandle(handle, conf.Skin) return incoming{s: s, w: w, conf: conf, p: &onlinePlayer{name: conf.Name, xuid: conf.XUID, handle: handle}} } diff --git a/server/world/entity.go b/server/world/entity.go index 59138f1ec..b6387f58a 100644 --- a/server/world/entity.go +++ b/server/world/entity.go @@ -85,7 +85,7 @@ func (opts EntitySpawnOpts) New(t EntityType, conf EntityConfig) *EntityHandle { } handle := &EntityHandle{id: opts.ID, t: t, cond: sync.NewCond(&sync.Mutex{}), worldless: &atomic.Bool{}} handle.worldless.Store(true) - handle.data.Pos, handle.data.Rot, handle.data.Vel = opts.Position, opts.Rotation, opts.Velocity + handle.data.pos, handle.data.rot, handle.data.Vel = opts.Position, opts.Rotation, opts.Velocity handle.data.Name = opts.NameTag conf.Apply(&handle.data) return handle @@ -265,9 +265,9 @@ func (e *EntityHandle) setAndUnlockWorld(w *World) { // decodeNBT decodes the position, velocity, rotation, age, on-fire duration and // name tag of an entity. func (e *EntityHandle) decodeNBT(m map[string]any) { - e.data.Pos = readVec3(m, "Pos") + e.data.pos = readVec3(m, "Pos") e.data.Vel = readVec3(m, "Motion") - e.data.Rot = readRotation(m) + e.data.rot = readRotation(m) e.data.Age = time.Duration(readInt16(m, "Age")) * (time.Second / 20) e.data.FireDuration = time.Duration(readInt16(m, "Fire")) * time.Second / 20 e.data.Name, _ = m["NameTag"].(string) @@ -277,10 +277,10 @@ func (e *EntityHandle) decodeNBT(m map[string]any) { // name tag of an entity. func (e *EntityHandle) encodeNBT() map[string]any { return map[string]any{ - "Pos": []float32{float32(e.data.Pos[0]), float32(e.data.Pos[1]), float32(e.data.Pos[2])}, + "Pos": []float32{float32(e.data.pos[0]), float32(e.data.pos[1]), float32(e.data.pos[2])}, "Motion": []float32{float32(e.data.Vel[0]), float32(e.data.Vel[1]), float32(e.data.Vel[2])}, - "Yaw": float32(e.data.Rot[0]), - "Pitch": float32(e.data.Rot[1]), + "Yaw": float32(e.data.rot[0]), + "Pitch": float32(e.data.rot[1]), "Fire": int16(e.data.FireDuration.Seconds() * 20), "Age": int16(e.data.Age / (time.Second * 20)), "NameTag": e.data.Name, @@ -289,8 +289,8 @@ func (e *EntityHandle) encodeNBT() map[string]any { // EntityData holds data shared by every entity. It is kept in an EntityHandle. type EntityData struct { - Pos, Vel mgl64.Vec3 - Rot cube.Rotation + pos, Vel mgl64.Vec3 + rot cube.Rotation Name string FireDuration time.Duration Age time.Duration @@ -298,19 +298,53 @@ type EntityData struct { Data any } +func (edata *EntityData) Velocity() mgl64.Vec3 { + return edata.Vel +} + func (edata *EntityData) SetVelocity(e Entity, tx *Tx, vel mgl64.Vec3) { if !vel.ApproxEqualThreshold(edata.Vel, epsilon) { // Only send velocity if the delta is big enough. - for _, v := range tx.Viewers(edata.Pos) { + for _, v := range tx.Viewers(edata.pos) { v.ViewEntityVelocity(e, vel) } } edata.Vel = vel } +func (edata *EntityData) Position() mgl64.Vec3 { + return edata.pos +} + +func (edata *EntityData) Rotation() cube.Rotation { + return edata.rot +} + +func (edata *EntityData) Teleport(e Entity, tx *Tx, pos mgl64.Vec3) { + edata.SetVelocity(e, tx, mgl64.Vec3{}) + for _, v := range tx.Viewers(edata.pos) { + v.ViewEntityTeleport(e, pos) + } + edata.setPosition(e, tx, pos, edata.rot) +} + +// epsilon is the epsilon used for thresholds for change used for change in +// position and velocity. +const epsilon = 0.001 + func (edata *EntityData) Move(e Entity, tx *Tx, pos mgl64.Vec3, rot cube.Rotation, onGround bool) { - prevChunkPos, chunkPos := chunkPosFromVec3(edata.Pos), chunkPosFromVec3(pos) - edata.updatePosition(e, tx, pos, rot, onGround) + if !pos.ApproxEqualThreshold(edata.pos, epsilon) || !mgl64.Vec2(rot).ApproxEqualThreshold(mgl64.Vec2(edata.rot), epsilon) { + // Only send movement if the delta of either rotation or position is + // significant enough. + for _, v := range tx.Viewers(edata.pos) { + v.ViewEntityMovement(e, pos, rot, onGround) + } + } + edata.setPosition(e, tx, pos, rot) +} + +func (edata *EntityData) setPosition(e Entity, tx *Tx, pos mgl64.Vec3, rot cube.Rotation) { + prevChunkPos, chunkPos := chunkPosFromVec3(edata.pos), chunkPosFromVec3(pos) if prevChunkPos == chunkPos { // Entity remains in the same chunk. return @@ -330,6 +364,7 @@ func (edata *EntityData) Move(e Entity, tx *Tx, pos mgl64.Vec3, rot cube.Rotatio viewer.HideEntity(e) } } + edata.pos, edata.rot = pos, rot for _, viewer := range chunk.viewers { if slices.Index(prevChunk.viewers, viewer) == -1 { // Then we show the entity to all loaders that are now viewing the @@ -339,21 +374,6 @@ func (edata *EntityData) Move(e Entity, tx *Tx, pos mgl64.Vec3, rot cube.Rotatio } } -// epsilon is the epsilon used for thresholds for change used for change in -// position and velocity. -const epsilon = 0.001 - -func (edata *EntityData) updatePosition(e Entity, tx *Tx, pos mgl64.Vec3, rot cube.Rotation, onGround bool) { - if !pos.ApproxEqualThreshold(edata.Pos, epsilon) || !mgl64.Vec2(rot).ApproxEqualThreshold(mgl64.Vec2(edata.Rot), epsilon) { - // Only send movement if the delta of either rotation or position is - // significant enough. - for _, v := range tx.Viewers(edata.Pos) { - v.ViewEntityMovement(e, pos, rot, onGround) - } - } - edata.Pos, edata.Rot = pos, rot -} - // Entity represents an Entity in the world, typically an object that may be moved around and can be // interacted with by other entities. // Viewers of a world may view an Entity when near it. diff --git a/server/world/world.go b/server/world/world.go index fc614c399..28532813e 100644 --- a/server/world/world.go +++ b/server/world/world.go @@ -661,7 +661,7 @@ func (w *World) playSound(tx *Tx, pos mgl64.Vec3, s Sound) { // addEntity returns the Entity created by the EntityHandle. func (w *World) addEntity(tx *Tx, handle *EntityHandle) Entity { handle.setAndUnlockWorld(w) - pos := chunkPosFromVec3(handle.data.Pos) + pos := chunkPosFromVec3(handle.data.pos) w.entities[handle] = struct{}{} c := w.chunk(pos) @@ -713,7 +713,7 @@ func (w *World) entitiesWithin(tx *Tx, box cube.BBox) iter.Seq[Entity] { continue } for _, handle := range c.Entities { - if !box.Vec3Within(handle.data.Pos) { + if !box.Vec3Within(handle.data.pos) { continue } if !yield(handle.mustEntity(tx)) {