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

world/viewer.go: Allow for more complex entity animations to be played #940

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions server/session/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -976,9 +976,12 @@ func (s *Session) ViewEntityState(e world.Entity) {
}

// ViewEntityAnimation ...
func (s *Session) ViewEntityAnimation(e world.Entity, animationName string) {
func (s *Session) ViewEntityAnimation(e world.Entity, a world.EntityAnimation) {
s.writePacket(&packet.AnimateEntity{
Animation: animationName,
Animation: a.Name(),
NextState: a.NextState(),
StopCondition: a.StopCondition(),
Controller: a.Controller(),
EntityRuntimeIDs: []uint64{
s.entityRuntimeID(e),
},
Expand Down
63 changes: 63 additions & 0 deletions server/world/entity_animation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package world

// EntityAnimation represents an animation that may be played on an entity from an active resource pack on
// the client.
type EntityAnimation struct {
name string
nextState string
controller string
stopCondition string
Sandertv marked this conversation as resolved.
Show resolved Hide resolved
}

// NewEntityAnimation returns a new animation that can be played on an entity. If no controller or stop
// condition is set, the animation will play for its full duration, including looping. Controllers can be set
// to manage multiple states of animations. It is also possible to use vanilla animations/controllers if they
// work for your entity, i.e. "animation.pig.baby_transform".
func NewEntityAnimation(name string) EntityAnimation {
return EntityAnimation{name: name}
}

// Name returns the name of the animation to be played.
func (a EntityAnimation) Name() string {
return a.name
}

// Controller returns the name of the controller to be used for the animation.
func (a EntityAnimation) Controller() string {
return a.controller
}

// WithController returns a copy of the EntityAnimation with the provided animation controller. An animation
// controller with the same name must be defined in a resource pack for it to work.
func (a EntityAnimation) WithController(controller string) EntityAnimation {
a.controller = controller
return a
}

// NextState returns the state to transition to after the animation has finished playing within the
DaPigGuy marked this conversation as resolved.
Show resolved Hide resolved
// animation controller.
func (a EntityAnimation) NextState() string {
return a.nextState
}

// WithNextState returns a copy of the EntityAnimation with the provided state to transition to after the
// animation has finished playing within the animation controller.
func (a EntityAnimation) WithNextState(state string) EntityAnimation {
a.nextState = state
return a
}

// StopCondition returns the condition that must be met for the animation to stop playing. This is often
// a Molang expression that can be used to query various entity properties to determine when the animation
// should stop playing.
func (a EntityAnimation) StopCondition() string {
return a.stopCondition
}

// WithStopCondition returns a copy of the EntityAnimation with the provided stop condition. The stop condition
// is a Molang expression that can be used to query various entity properties to determine when the animation
// should stop playing.
func (a EntityAnimation) WithStopCondition(condition string) EntityAnimation {
a.stopCondition = condition
return a
}
8 changes: 8 additions & 0 deletions server/world/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ func (tx *Tx) AddParticle(pos mgl64.Vec3, p Particle) {
tx.World().addParticle(pos, p)
}

// PlayEntityAnimation plays an animation on an entity in the World. The animation is played for all viewers
// of the entity.
func (tx *Tx) PlayEntityAnimation(e Entity, a EntityAnimation) {
for _, viewer := range tx.World().viewersOf(e.Position()) {
viewer.ViewEntityAnimation(e, a)
}
}

// PlaySound plays a sound at a specific position in the World. Viewers of that
// position will be able to hear the sound if they are close enough.
func (tx *Tx) PlaySound(pos mgl64.Vec3, s Sound) {
Expand Down
6 changes: 3 additions & 3 deletions server/world/viewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ type Viewer interface {
// ViewEntityState views the current state of an Entity. It is called whenever an Entity changes its
// physical appearance, for example when sprinting.
ViewEntityState(e Entity)
// ViewEntityAnimation starts viewing an animation performed by an Entity. The animation has to be from a resource pack.
ViewEntityAnimation(e Entity, animationName string)
// ViewEntityAnimation starts viewing an animation performed by an Entity.
ViewEntityAnimation(e Entity, a EntityAnimation)
// ViewParticle views a particle spawned at a given position in the world. It is called when a particle,
// for example a block breaking particle, is spawned near the player.
ViewParticle(pos mgl64.Vec3, p Particle)
Expand Down Expand Up @@ -91,7 +91,7 @@ func (NopViewer) ViewEntityItems(Entity)
func (NopViewer) ViewEntityArmour(Entity) {}
func (NopViewer) ViewEntityAction(Entity, EntityAction) {}
func (NopViewer) ViewEntityState(Entity) {}
func (NopViewer) ViewEntityAnimation(Entity, string) {}
func (NopViewer) ViewEntityAnimation(Entity, EntityAnimation) {}
func (NopViewer) ViewParticle(mgl64.Vec3, Particle) {}
func (NopViewer) ViewSound(mgl64.Vec3, Sound) {}
func (NopViewer) ViewBlockUpdate(cube.Pos, Block, int) {}
Expand Down
Loading