2023-04-08 13:58:47 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-05-31 00:37:51 -06:00
|
|
|
"time"
|
2023-06-01 13:11:32 -06:00
|
|
|
"errors"
|
2023-04-08 13:58:47 -06:00
|
|
|
)
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
type Member struct {
|
|
|
|
BaseResource
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewMember(name string) * Member {
|
|
|
|
member := &Member{
|
2023-06-01 22:42:47 -06:00
|
|
|
BaseResource: NewBaseResource(name, "A Team Member", []Resource{}),
|
2023-05-30 20:45:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return member
|
|
|
|
}
|
|
|
|
|
2023-04-08 13:58:47 -06:00
|
|
|
type Team struct {
|
|
|
|
BaseResource
|
|
|
|
Org string
|
|
|
|
Team string
|
|
|
|
}
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
func (team * Team) Members() []*Member {
|
|
|
|
ret := make([]*Member, len(team.children))
|
|
|
|
for idx, member := range(team.children) {
|
|
|
|
ret[idx] = member.(*Member)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTeam(org string, team string, members []*Member) * Team {
|
2023-04-08 13:58:47 -06:00
|
|
|
name := fmt.Sprintf("%s%s", org, team)
|
|
|
|
description := fmt.Sprintf("Team %s", name)
|
|
|
|
resource := &Team{
|
2023-06-01 22:42:47 -06:00
|
|
|
BaseResource: NewBaseResource(name, description, make([]Resource, len(members))),
|
2023-04-08 13:58:47 -06:00
|
|
|
Org: org,
|
|
|
|
Team: team,
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
for idx, member := range(members) {
|
|
|
|
resource.children[idx] = member
|
|
|
|
}
|
2023-06-01 22:42:47 -06:00
|
|
|
|
2023-04-08 13:58:47 -06:00
|
|
|
return resource
|
|
|
|
}
|
|
|
|
|
|
|
|
type Alliance struct {
|
|
|
|
BaseResource
|
2023-06-08 00:36:16 -06:00
|
|
|
teams []*Team
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewAlliance(team0 * Team, team1 * Team) * Alliance {
|
|
|
|
name := fmt.Sprintf("Alliance %s/%s", team0.Name(), team1.Name())
|
|
|
|
description := ""
|
|
|
|
|
|
|
|
resource := &Alliance{
|
2023-06-01 22:42:47 -06:00
|
|
|
BaseResource: NewBaseResource(name, description, []Resource{team0, team1}),
|
2023-06-08 00:36:16 -06:00
|
|
|
teams: []*Team{team0, team1},
|
2023-04-08 13:58:47 -06:00
|
|
|
}
|
|
|
|
return resource
|
|
|
|
}
|
2023-05-30 20:45:16 -06:00
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
type Arena interface {
|
|
|
|
Resource
|
|
|
|
}
|
|
|
|
|
|
|
|
type VirtualArena struct {
|
2023-06-01 13:11:32 -06:00
|
|
|
BaseResource
|
|
|
|
connected bool
|
|
|
|
}
|
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
func NewVirtualArena(name string) * VirtualArena {
|
|
|
|
arena := &VirtualArena{
|
2023-06-01 22:42:47 -06:00
|
|
|
BaseResource: NewBaseResource(name, "A virtual vex arena", []Resource{}),
|
2023-06-01 13:11:32 -06:00
|
|
|
connected: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
return arena
|
|
|
|
}
|
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
func (arena * VirtualArena) lock(node GraphNode) error {
|
2023-06-01 13:11:32 -06:00
|
|
|
if arena.connected == false {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "ARENA NOT CONNECTED: %s", arena.Name())
|
2023-06-01 13:11:32 -06:00
|
|
|
error_str := fmt.Sprintf("%s is not connected, cannot lock", arena.Name())
|
|
|
|
return errors.New(error_str)
|
|
|
|
}
|
2023-06-02 17:31:29 -06:00
|
|
|
return nil
|
2023-06-01 13:11:32 -06:00
|
|
|
}
|
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
func (arena * VirtualArena) update(signal GraphSignal) {
|
2023-06-02 17:31:29 -06:00
|
|
|
arena.signal <- signal
|
2023-06-03 18:56:14 -06:00
|
|
|
arena.BaseResource.update(signal)
|
2023-06-01 22:42:47 -06:00
|
|
|
}
|
|
|
|
|
2023-06-06 16:53:33 -06:00
|
|
|
func (arena * VirtualArena) Init(abort chan error) bool {
|
|
|
|
log.Logf("vex", "Initializing %s", arena.Name())
|
2023-06-04 17:23:49 -06:00
|
|
|
go func(arena * VirtualArena, abort chan error) {
|
2023-06-01 13:11:32 -06:00
|
|
|
update_str := fmt.Sprintf("VIRTUAL_ARENA connected: %s", arena.Name())
|
2023-06-03 10:59:42 -06:00
|
|
|
signal := NewSignal(arena, "resource_connected")
|
2023-06-01 22:42:47 -06:00
|
|
|
signal.description = update_str
|
2023-06-02 17:31:29 -06:00
|
|
|
arena.connected = true
|
2023-06-03 01:38:35 -06:00
|
|
|
go SendUpdate(arena, signal)
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "VIRTUAL_ARENA goroutine starting: %s", arena.Name())
|
2023-06-01 13:11:32 -06:00
|
|
|
for true {
|
|
|
|
select {
|
|
|
|
case <- abort:
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "Virtual arena %s aborting", arena.Name())
|
2023-06-01 13:11:32 -06:00
|
|
|
break
|
2023-06-01 22:42:47 -06:00
|
|
|
case update := <- arena.signal:
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "VIRTUAL_ARENA_ACTION: %s : %+v", arena.Name(), update)
|
2023-06-01 13:11:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}(arena, abort)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
type VexEvent struct {
|
|
|
|
BaseEvent
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewVexEvent(name string, description string) * VexEvent {
|
|
|
|
event := &VexEvent{
|
|
|
|
BaseEvent: NewBaseEvent(name, description, []Resource{}),
|
|
|
|
}
|
|
|
|
|
|
|
|
event.actions["wait"] = EventWait(event)
|
2023-06-06 23:04:49 -06:00
|
|
|
event.handlers["abort"] = EventAbort(event)
|
2023-06-04 17:23:49 -06:00
|
|
|
event.actions["start"] = func() (string, error) {
|
|
|
|
log.Logf("vex", "STARTING_VEX_TOURNAMENT %s", event.Name())
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return event
|
|
|
|
}
|
|
|
|
|
2023-06-04 13:18:10 -06:00
|
|
|
const start_slack = 250 * time.Millisecond
|
2023-06-16 01:46:15 -06:00
|
|
|
const TEMP_AUTON_TIME = 1 * time.Second
|
|
|
|
const TEMP_DRIVE_TIME = 1 * time.Second
|
2023-05-31 00:37:51 -06:00
|
|
|
|
2023-06-03 02:45:16 -06:00
|
|
|
type Match struct {
|
|
|
|
BaseEvent
|
2023-06-04 17:23:49 -06:00
|
|
|
arena Arena
|
2023-06-03 02:45:16 -06:00
|
|
|
state string
|
|
|
|
control string
|
|
|
|
control_start time.Time
|
2023-06-08 00:19:55 -06:00
|
|
|
alliances []*Alliance
|
2023-06-03 02:45:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (match * Match) update(signal GraphSignal) {
|
|
|
|
new_signal := signal.Trace(match.ID())
|
|
|
|
match.BaseEvent.update(new_signal)
|
|
|
|
}
|
|
|
|
|
2023-06-04 17:23:49 -06:00
|
|
|
func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena Arena) * Match {
|
2023-06-01 13:11:32 -06:00
|
|
|
name := fmt.Sprintf("Match: %s vs. %s on %s", alliance0.Name(), alliance1.Name(), arena.Name())
|
2023-05-30 20:45:16 -06:00
|
|
|
description := "A vex match"
|
|
|
|
|
|
|
|
match := &Match{
|
|
|
|
BaseEvent: NewBaseEvent(name, description, []Resource{alliance0, alliance1, arena}),
|
2023-05-30 21:50:59 -06:00
|
|
|
state: "init",
|
2023-05-31 00:37:51 -06:00
|
|
|
control: "init",
|
|
|
|
control_start: time.UnixMilli(0),
|
2023-06-03 02:45:16 -06:00
|
|
|
arena: arena,
|
2023-06-08 00:19:55 -06:00
|
|
|
alliances: []*Alliance{alliance0, alliance1},
|
2023-05-30 20:45:16 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
match.actions["wait"] = EventWait(match)
|
2023-06-06 23:04:49 -06:00
|
|
|
match.handlers["abort"] = EventAbort(match)
|
2023-06-03 23:49:25 -06:00
|
|
|
|
2023-05-30 21:50:59 -06:00
|
|
|
match.actions["start"] = func() (string, error) {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "STARTING_MATCH %s", match.Name())
|
2023-05-31 00:37:51 -06:00
|
|
|
match.control = "none"
|
2023-05-30 21:50:59 -06:00
|
|
|
match.state = "scheduled"
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
match.handlers["queue_autonomous"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "scheduled" {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "AUTONOMOUS_QUEUED: %s", match.Name())
|
2023-05-31 00:37:51 -06:00
|
|
|
match.control = "none"
|
|
|
|
match.state = "autonomous_queued"
|
|
|
|
match.control_start = time.Now().Add(start_slack)
|
2023-06-03 18:56:14 -06:00
|
|
|
new_signal := NewSignal(match, "autonomous_queued")
|
|
|
|
new_signal.time = match.control_start
|
|
|
|
go SendUpdate(match, new_signal)
|
2023-05-31 00:37:51 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
match.handlers["start_autonomous"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "autonomous_queued" {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "AUTONOMOUS_RUNNING: %s", match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
match.control = "program"
|
2023-05-31 00:37:51 -06:00
|
|
|
match.state = "autonomous_running"
|
2023-06-03 01:38:35 -06:00
|
|
|
match.control_start = signal.Time()
|
|
|
|
go SendUpdate(match, NewSignal(match, "autonomous_running"))
|
2023-06-03 23:49:25 -06:00
|
|
|
|
|
|
|
end_time := match.control_start.Add(TEMP_AUTON_TIME)
|
|
|
|
match.SetTimeout(end_time, "autonomous_done")
|
2023-06-16 01:46:15 -06:00
|
|
|
log.Logf("vex", "AUTONOMOUS@%s: %s UNTIL %s", time.Now(), match.control_start, end_time)
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
match.handlers["autonomous_done"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "autonomous_running" {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "AUTONOMOUS_DONE: %s", match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
match.control = "none"
|
|
|
|
match.state = "autonomous_done"
|
|
|
|
|
2023-05-30 21:50:59 -06:00
|
|
|
return "wait", nil
|
2023-05-30 20:45:16 -06:00
|
|
|
}
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
match.handlers["queue_driver"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "autonomous_done"{
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
match.control = "none"
|
|
|
|
match.state = "driver_queued"
|
|
|
|
match.control_start = time.Now().Add(start_slack)
|
2023-06-03 18:56:14 -06:00
|
|
|
new_signal := NewSignal(match, "driver_queued")
|
|
|
|
new_signal.time = match.control_start
|
|
|
|
go SendUpdate(match, new_signal)
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
match.handlers["start_driver"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "driver_queued" {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
match.control = "driver"
|
|
|
|
match.state = "driver_running"
|
|
|
|
match.control_start = signal.Time()
|
|
|
|
|
|
|
|
go SendUpdate(match, NewSignal(match, "driver_running"))
|
2023-06-03 23:49:25 -06:00
|
|
|
|
|
|
|
end_time := match.control_start.Add(TEMP_DRIVE_TIME)
|
|
|
|
match.SetTimeout(end_time, "driver_done")
|
|
|
|
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
match.handlers["driver_done"] = func(signal GraphSignal) (string, error) {
|
|
|
|
if match.state != "driver_running" {
|
2023-06-04 13:18:10 -06:00
|
|
|
log.Logf("vex", "BAD_STATE: %s: %s - %s", signal.Type(), match.state, match.Name())
|
2023-06-03 01:38:35 -06:00
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
match.control = "none"
|
|
|
|
match.state = "driver_done"
|
|
|
|
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2023-06-03 23:49:25 -06:00
|
|
|
match.actions["driver_done"] = func() (string, error) {
|
2023-06-04 17:23:49 -06:00
|
|
|
new_signal := NewSignal(match, "driver_done")
|
|
|
|
new_signal.time = time.Now()
|
2023-06-03 23:49:25 -06:00
|
|
|
SendUpdate(match, NewSignal(match, "driver_done"))
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
match.actions["autonomous_done"] = func() (string, error) {
|
|
|
|
SendUpdate(match, NewSignal(match, "autonomous_done"))
|
|
|
|
return "wait", nil
|
|
|
|
}
|
|
|
|
|
2023-05-30 20:45:16 -06:00
|
|
|
return match
|
|
|
|
}
|