178 lines
4.7 KiB
Go
178 lines
4.7 KiB
Go
|
|
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)
|
||
|
|
}
|
||
|
|
}
|