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

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package publisher
  2. import (
  3. "git.aiterp.net/lucifer/new-server/models"
  4. "time"
  5. )
  6. type Scene struct {
  7. data *models.Scene
  8. group string
  9. startTime time.Time
  10. endTime time.Time
  11. roleMap map[int]int
  12. roleList map[int][]models.Device
  13. due bool
  14. lastInterval int64
  15. }
  16. // UpdateScene updates the scene data and re-seats all devices.
  17. func (s *Scene) UpdateScene(data models.Scene) {
  18. devices := make([]models.Device, 0, 16)
  19. // Collect all devices into the undefined role (-1)
  20. for _, list := range s.roleList {
  21. for _, device := range list {
  22. devices = append(devices, device)
  23. s.roleMap[device.ID] = -1
  24. }
  25. }
  26. s.roleList = map[int][]models.Device{-1: devices}
  27. // Update data and reset devices.
  28. s.data = &data
  29. for _, device := range append(devices[:0:0], devices...) {
  30. s.UpsertDevice(device)
  31. }
  32. }
  33. // UpsertDevice moves the device if necessary and updates its state.
  34. func (s *Scene) UpsertDevice(device models.Device) {
  35. if s.data == nil {
  36. s.roleMap[device.ID] = -1
  37. s.roleList[-1] = append(s.roleList[-1], device)
  38. return
  39. }
  40. oldIndex, hasOldIndex := s.roleMap[device.ID]
  41. newIndex := s.data.RoleIndex(&device)
  42. s.roleMap[device.ID] = newIndex
  43. if hasOldIndex {
  44. for i, device2 := range s.roleList[oldIndex] {
  45. if device2.ID == device.ID {
  46. s.roleList[oldIndex] = append(s.roleList[oldIndex][:i], s.roleList[oldIndex][i+1:]...)
  47. break
  48. }
  49. }
  50. }
  51. s.due = true
  52. s.roleList[newIndex] = append(s.roleList[newIndex], device)
  53. if newIndex != -1 {
  54. s.data.Roles[newIndex].ApplyOrder(s.roleList[newIndex])
  55. }
  56. }
  57. // RemoveDevice finds and remove a device. It's a noop if the device does not exist in this scene.
  58. func (s *Scene) RemoveDevice(device models.Device) {
  59. roleIndex, hasRoleIndex := s.roleMap[device.ID]
  60. if !hasRoleIndex {
  61. return
  62. }
  63. for i, device2 := range s.roleList[roleIndex] {
  64. if device2.ID == device.ID {
  65. s.roleList[roleIndex] = append(s.roleList[roleIndex][:i], s.roleList[roleIndex][i+1:]...)
  66. break
  67. }
  68. }
  69. s.due = true
  70. delete(s.roleMap, device.ID)
  71. }
  72. func (s *Scene) Empty() bool {
  73. for _, list := range s.roleList {
  74. if len(list) > 0 {
  75. return false
  76. }
  77. }
  78. return true
  79. }
  80. func (s *Scene) Due() bool {
  81. if s.due {
  82. return true
  83. }
  84. if s.data.IntervalMS > 0 {
  85. interval := time.Duration(s.data.IntervalMS) * time.Millisecond
  86. return int64(time.Since(s.startTime)/interval) != s.lastInterval
  87. }
  88. return false
  89. }
  90. func (s *Scene) UnaffectedDevices() []models.Device {
  91. return append(s.roleList[-1][:0:0], s.roleList[-1]...)
  92. }
  93. func (s *Scene) AllDevices() []models.Device {
  94. res := make([]models.Device, 0, 16)
  95. for _, list := range s.roleList {
  96. res = append(res, list...)
  97. }
  98. return res
  99. }
  100. // Run runs the scene
  101. func (s *Scene) Run() []models.Device {
  102. if s.data == nil {
  103. return []models.Device{}
  104. }
  105. intervalNumber := int64(0)
  106. intervalMax := int64(1)
  107. if s.data.IntervalMS > 0 {
  108. interval := time.Duration(s.data.IntervalMS) * time.Millisecond
  109. intervalNumber = int64(time.Since(s.startTime) / interval)
  110. if !s.endTime.IsZero() {
  111. intervalMax = int64(s.endTime.Sub(s.startTime) / interval)
  112. } else {
  113. intervalMax = intervalNumber + 1
  114. }
  115. }
  116. updatedDevices := make([]models.Device, 0, 16)
  117. for i, list := range s.roleList {
  118. if i == -1 {
  119. continue
  120. }
  121. role := s.data.Roles[i]
  122. for j, device := range list {
  123. newState := role.ApplyEffect(&device, models.SceneRunContext{
  124. Index: j,
  125. Length: len(list),
  126. IntervalNumber: intervalNumber,
  127. IntervalMax: intervalMax,
  128. })
  129. err := device.SetState(newState)
  130. if err != nil {
  131. continue
  132. }
  133. updatedDevices = append(updatedDevices, device)
  134. }
  135. }
  136. s.due = false
  137. s.lastInterval = intervalNumber
  138. return updatedDevices
  139. }