You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
3.6 KiB
174 lines
3.6 KiB
package publisher
|
|
|
|
import (
|
|
"git.aiterp.net/lucifer/new-server/models"
|
|
"time"
|
|
)
|
|
|
|
type Scene struct {
|
|
data *models.Scene
|
|
group string
|
|
startTime time.Time
|
|
endTime time.Time
|
|
roleMap map[int]int
|
|
roleList map[int][]models.Device
|
|
|
|
due bool
|
|
lastInterval int64
|
|
}
|
|
|
|
// UpdateScene updates the scene data and re-seats all devices.
|
|
func (s *Scene) UpdateScene(data models.Scene) {
|
|
devices := make([]models.Device, 0, 16)
|
|
|
|
// Collect all devices into the undefined role (-1)
|
|
for _, list := range s.roleList {
|
|
for _, device := range list {
|
|
devices = append(devices, device)
|
|
s.roleMap[device.ID] = -1
|
|
}
|
|
}
|
|
s.roleList = map[int][]models.Device{-1: devices}
|
|
|
|
// Update data and reset devices.
|
|
s.data = &data
|
|
for _, device := range append(devices[:0:0], devices...) {
|
|
s.UpsertDevice(device)
|
|
}
|
|
}
|
|
|
|
// UpsertDevice moves the device if necessary and updates its state.
|
|
func (s *Scene) UpsertDevice(device models.Device) {
|
|
if s.data == nil {
|
|
s.roleMap[device.ID] = -1
|
|
s.roleList[-1] = append(s.roleList[-1], device)
|
|
return
|
|
}
|
|
|
|
oldIndex, hasOldIndex := s.roleMap[device.ID]
|
|
newIndex := s.data.RoleIndex(&device)
|
|
|
|
s.roleMap[device.ID] = newIndex
|
|
|
|
if hasOldIndex {
|
|
for i, device2 := range s.roleList[oldIndex] {
|
|
if device2.ID == device.ID {
|
|
s.roleList[oldIndex] = append(s.roleList[oldIndex][:i], s.roleList[oldIndex][i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
s.due = true
|
|
|
|
s.roleList[newIndex] = append(s.roleList[newIndex], device)
|
|
if newIndex != -1 {
|
|
s.data.Roles[newIndex].ApplyOrder(s.roleList[newIndex])
|
|
}
|
|
}
|
|
|
|
// RemoveDevice finds and remove a device. It's a noop if the device does not exist in this scene.
|
|
func (s *Scene) RemoveDevice(device models.Device) {
|
|
roleIndex, hasRoleIndex := s.roleMap[device.ID]
|
|
if !hasRoleIndex {
|
|
return
|
|
}
|
|
|
|
for i, device2 := range s.roleList[roleIndex] {
|
|
if device2.ID == device.ID {
|
|
s.roleList[roleIndex] = append(s.roleList[roleIndex][:i], s.roleList[roleIndex][i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
|
|
s.due = true
|
|
|
|
delete(s.roleMap, device.ID)
|
|
}
|
|
|
|
func (s *Scene) Empty() bool {
|
|
for _, list := range s.roleList {
|
|
if len(list) > 0 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
|
|
func (s *Scene) Due() bool {
|
|
if s.due {
|
|
return true
|
|
}
|
|
|
|
if s.data.IntervalMS > 0 {
|
|
interval := time.Duration(s.data.IntervalMS) * time.Millisecond
|
|
return int64(time.Since(s.startTime)/interval) != s.lastInterval
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (s *Scene) UnaffectedDevices() []models.Device {
|
|
return append(s.roleList[-1][:0:0], s.roleList[-1]...)
|
|
}
|
|
|
|
func (s *Scene) AllDevices() []models.Device {
|
|
res := make([]models.Device, 0, 16)
|
|
for _, list := range s.roleList {
|
|
res = append(res, list...)
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
// Run runs the scene
|
|
func (s *Scene) Run() []models.Device {
|
|
if s.data == nil {
|
|
return []models.Device{}
|
|
}
|
|
|
|
intervalNumber := int64(0)
|
|
intervalMax := int64(1)
|
|
if s.data.IntervalMS > 0 {
|
|
interval := time.Duration(s.data.IntervalMS) * time.Millisecond
|
|
intervalNumber = int64(time.Since(s.startTime) / interval)
|
|
|
|
if !s.endTime.IsZero() {
|
|
intervalMax = int64(s.endTime.Sub(s.startTime) / interval)
|
|
} else {
|
|
intervalMax = intervalNumber + 1
|
|
}
|
|
}
|
|
|
|
updatedDevices := make([]models.Device, 0, 16)
|
|
for i, list := range s.roleList {
|
|
if i == -1 {
|
|
continue
|
|
}
|
|
|
|
role := s.data.Roles[i]
|
|
|
|
for j, device := range list {
|
|
newState := role.ApplyEffect(&device, models.SceneRunContext{
|
|
Index: j,
|
|
Length: len(list),
|
|
IntervalNumber: intervalNumber,
|
|
IntervalMax: intervalMax,
|
|
})
|
|
|
|
err := device.SetState(newState)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
updatedDevices = append(updatedDevices, device)
|
|
}
|
|
}
|
|
|
|
s.due = false
|
|
s.lastInterval = intervalNumber
|
|
|
|
return updatedDevices
|
|
}
|