up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// layer stores the appearance overrides that a ViewLayer applies to an entity.
|
||||
type layer struct {
|
||||
nameTag *string
|
||||
scoreTag *string
|
||||
visibility VisibilityLevel
|
||||
}
|
||||
|
||||
// ViewLayerUpdater handles immediate updates after a ViewLayer changes how an entity is viewed.
|
||||
type ViewLayerUpdater interface {
|
||||
// ViewLayerEntityChanged handles an entity whose view-layer overrides changed.
|
||||
ViewLayerEntityChanged(entity Entity)
|
||||
}
|
||||
|
||||
type viewLayerViewer interface {
|
||||
ViewLayer() *ViewLayer
|
||||
}
|
||||
|
||||
// ViewLayer holds overrides for how entities are viewed by a single viewer. It allows entities to be
|
||||
// viewed differently by different players, such as with a different name tag or visibility state.
|
||||
type ViewLayer struct {
|
||||
mu sync.RWMutex
|
||||
entities map[*EntityHandle]layer
|
||||
updater ViewLayerUpdater
|
||||
}
|
||||
|
||||
// NewViewLayer returns a new ViewLayer.
|
||||
func NewViewLayer(updater ViewLayerUpdater) *ViewLayer {
|
||||
return &ViewLayer{
|
||||
entities: map[*EntityHandle]layer{},
|
||||
updater: updater,
|
||||
}
|
||||
}
|
||||
|
||||
// Entities returns the handles of all entities with overrides in the view layer.
|
||||
func (v *ViewLayer) Entities() []*EntityHandle {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
|
||||
return slices.Collect(maps.Keys(v.entities))
|
||||
}
|
||||
|
||||
// ViewNameTag overwrites the public name tag of the entity and allows this ViewLayer to view a different name tag.
|
||||
// Passing an empty name tag removes the name tag for this ViewLayer.
|
||||
func (v *ViewLayer) ViewNameTag(entity Entity, nameTag string) {
|
||||
v.update(entity, func(l *layer) {
|
||||
l.nameTag = &nameTag
|
||||
})
|
||||
}
|
||||
|
||||
// ViewPublicNameTag removes the name tag override from the entity, causing the public name tag to be
|
||||
// viewed again.
|
||||
func (v *ViewLayer) ViewPublicNameTag(entity Entity) {
|
||||
v.update(entity, func(l *layer) {
|
||||
l.nameTag = nil
|
||||
})
|
||||
}
|
||||
|
||||
// NameTag returns the overwritten name tag of the entity and whether an override was set.
|
||||
func (v *ViewLayer) NameTag(entity Entity) (string, bool) {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
|
||||
nameTag := v.entities[entity.H()].nameTag
|
||||
if nameTag == nil {
|
||||
return "", false
|
||||
}
|
||||
return *nameTag, true
|
||||
}
|
||||
|
||||
// ViewScoreTag overwrites the public score tag of the entity and allows this ViewLayer to view a different score tag.
|
||||
// Passing an empty score tag removes the score tag for this ViewLayer.
|
||||
func (v *ViewLayer) ViewScoreTag(entity Entity, scoreTag string) {
|
||||
v.update(entity, func(l *layer) {
|
||||
l.scoreTag = &scoreTag
|
||||
})
|
||||
}
|
||||
|
||||
// ViewPublicScoreTag removes the score tag override from the entity, causing the public score tag to be
|
||||
// viewed again.
|
||||
func (v *ViewLayer) ViewPublicScoreTag(entity Entity) {
|
||||
v.update(entity, func(l *layer) {
|
||||
l.scoreTag = nil
|
||||
})
|
||||
}
|
||||
|
||||
// ScoreTag returns the overwritten score tag of the entity and whether an override was set.
|
||||
func (v *ViewLayer) ScoreTag(entity Entity) (string, bool) {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
|
||||
scoreTag := v.entities[entity.H()].scoreTag
|
||||
if scoreTag == nil {
|
||||
return "", false
|
||||
}
|
||||
return *scoreTag, true
|
||||
}
|
||||
|
||||
// ViewVisibility overwrites the public visibility of the entity and allows this ViewLayer to view
|
||||
// this entity as (in)visible depending on the VisibilityLevel.
|
||||
func (v *ViewLayer) ViewVisibility(entity Entity, level VisibilityLevel) {
|
||||
v.update(entity, func(l *layer) {
|
||||
l.visibility = level
|
||||
})
|
||||
}
|
||||
|
||||
// Visibility returns the visibility of the entity.
|
||||
func (v *ViewLayer) Visibility(entity Entity) VisibilityLevel {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
|
||||
return v.entities[entity.H()].visibility
|
||||
}
|
||||
|
||||
// Remove removes all overrides for the entity from the ViewLayer.
|
||||
func (v *ViewLayer) Remove(entity Entity) {
|
||||
if v.remove(entity) {
|
||||
v.refresh(entity)
|
||||
}
|
||||
}
|
||||
|
||||
// remove removes all overrides for the entity from the ViewLayer without refreshing entity metadata. It returns
|
||||
// whether any overrides were removed.
|
||||
func (v *ViewLayer) remove(entity Entity) bool {
|
||||
handle := entity.H()
|
||||
|
||||
v.mu.Lock()
|
||||
_, ok := v.entities[handle]
|
||||
delete(v.entities, handle)
|
||||
v.mu.Unlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
// update applies a mutation to the entity's layer, removes the entry if no overrides remain, and refreshes
|
||||
// the entity for the layer's viewer.
|
||||
func (v *ViewLayer) update(entity Entity, update func(*layer)) {
|
||||
handle := entity.H()
|
||||
|
||||
v.mu.Lock()
|
||||
l := v.entities[handle]
|
||||
update(&l)
|
||||
if l.empty() {
|
||||
delete(v.entities, handle)
|
||||
} else {
|
||||
v.entities[handle] = l
|
||||
}
|
||||
v.mu.Unlock()
|
||||
|
||||
v.refresh(entity)
|
||||
}
|
||||
|
||||
// Close closes the view layer.
|
||||
func (v *ViewLayer) Close() error {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
|
||||
clear(v.entities)
|
||||
return nil
|
||||
}
|
||||
|
||||
// empty checks if the layer does not override any public entity metadata.
|
||||
func (l layer) empty() bool {
|
||||
return l.nameTag == nil && l.scoreTag == nil && l.visibility == PublicVisibility()
|
||||
}
|
||||
|
||||
func (v *ViewLayer) refresh(entity Entity) {
|
||||
if v.updater != nil {
|
||||
v.updater.ViewLayerEntityChanged(entity)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user