Skip to content

Commit e9f9a5b

Browse files
committed
WIP: Custom locations and VECTOR command
1 parent d5ba24c commit e9f9a5b

17 files changed

Lines changed: 210 additions & 63 deletions

File tree

cmd/skyeye/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ var (
7474
discordWebhookID string
7575
discordWebhookToken string
7676
exitAfter time.Duration
77+
locationsFile string
7778
)
7879

7980
func init() {
@@ -142,6 +143,7 @@ func init() {
142143
skyeye.Flags().DurationVar(&threatMonitoringInterval, "threat-monitoring-interval", 3*time.Minute, "How often to broadcast THREAT")
143144
skyeye.Flags().Float64Var(&mandatoryThreatRadiusNM, "mandatory-threat-radius", 25, "Briefed radius for mandatory THREAT calls, in nautical miles")
144145
skyeye.Flags().BoolVar(&threatMonitoringRequiresSRS, "threat-monitoring-requires-srs", true, "Require aircraft to be on SRS to receive THREAT calls. Only useful to disable when debugging")
146+
skyeye.Flags().StringVar(&locationsFile, "locations-file", "", "Path to file containing additional locations that may be referenced in ALPHA CHECK and VECTOR calls.")
145147

146148
// Tracing
147149
skyeye.Flags().BoolVar(&enableTracing, "enable-tracing", false, "Enable tracing")

docs/LOCATIONS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Custom Locations
2+
3+
Server administrators can define custom locations which players can reference in ALPHA CHECK and VECTOR requests. You can define useful locations like friendly bases or fix points.
4+
5+
To use this feature, create a `locations.json` file. The content of the file should be a JSON array of objects. Each object should have the following properties:
6+
7+
- `names`: An array of strings, which are the names of the location. These names are used in the ALPHA CHECK and VECTOR requests. You can define multiple names for the same location - for example, you might have a location with both the names "Incirlik" and "Home plate"
8+
- `latitude`: A floating point number, which is the latitude of the location in decimal degrees. This should be a number between -90 and 90.
9+
- `longitude`: A floating point number, which is the longitude of the location in decimal degrees. This should be a number between -180 and 180.
10+
11+
Example:
12+
13+
```json
14+
[
15+
{
16+
"names": ["Incirlik", "Home plate"],
17+
"latitude": 37.001166662,
18+
"longitude": 35.422164978
19+
},
20+
{
21+
"names": ["Hatay", "Divert option"],
22+
"latitude": 36.362778,
23+
"longitude": 36.282222
24+
}
25+
]
26+
```

docs/PLAYER.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ Tips:
168168

169169
Keyword: `ALPHA`
170170

171-
Function: The GCI will check if they see you on scope and tell you your approximate current location in bullseye format.
171+
Function: The GCI will check if they see you on scope and tell you your approximate current location as a bearing and range from a given point. You can ask for an Alpha Check from bullseye, or from a [named location](LOCATIONS.md). The bullseye is used if no point is specified.
172172

173173
Use: You can use this to coarsely check your INS navigation system in an aircraft without GPS. It is accurate to within several miles (accounting for potential lag time between when the bot checks the scope and when the response is sent on the radio).
174174

@@ -189,6 +189,21 @@ YELLOW 13: "Goliath Yellow One Three alpha"
189189
GOLIATH: "Yellow One Three, Goliath, contact, alpha check bullseye 088/5"
190190
```
191191

192+
### VECTOR
193+
194+
Keyword: `VECTOR`
195+
196+
Function: The GCI will check if you are on scope and tell you the approximate bearing and range from you to a given point. You can ask for a vector to bullseye, or to a [named location](LOCATIONS.md). The bullseye is used if no point is specified.
197+
198+
Use: This is the reciprocal of an ALPHA CHECK, and is useful for navigation assistance.
199+
200+
Examples:
201+
202+
```
203+
MOBIUS 1: "Thunderhead Mobius One vector to home plate."
204+
THUNDERHEAD: "Mobius One, Thunderhead, reference 215/55"
205+
```
206+
192207
### BOGEY DOPE
193208

194209
Keyword: `BOGEY`

internal/conf/configuration.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ type Configuration struct {
9191
// ThreatMonitoringRequiresSRS controls whether threat calls are issued to aircraft that are not on an SRS frequency. This is mostly
9292
// for debugging.
9393
ThreatMonitoringRequiresSRS bool
94+
// Locations is a slice of named locations that can be referenced in ALPHA CHECK and VECTOR calls.
95+
Locations []*Location
9496
// EnableTracing controls whether to publish traces
9597
EnableTracing bool
9698
// DiscordWebhookID is the ID of the Discord webhook
@@ -101,6 +103,13 @@ type Configuration struct {
101103
ExitAfter time.Duration
102104
}
103105

106+
type Location struct {
107+
// Names of the location
108+
Names []string `json:"names"`
109+
// Coordinates of the location as a GeoJSON coordinates array with a single member
110+
Coordinates [][]float64 `json:"coordinates"`
111+
}
112+
104113
var DefaultCallsigns = []string{"Sky Eye", "Thunderhead", "Eagle Eye", "Ghost Eye", "Sky Keeper", "Bandog", "Long Caster", "Galaxy"}
105114

106115
var DefaultPictureRadius = 300 * unit.NauticalMile

pkg/brevity/braa.go

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package brevity
22

33
import (
44
"fmt"
5-
"math"
65

76
"github.com/dharmab/skyeye/pkg/bearings"
87
"github.com/dharmab/skyeye/pkg/spatial"
@@ -20,20 +19,16 @@ type BRAA interface {
2019

2120
// BRA is an abbreviated form of BRAA without aspect.
2221
type BRA interface {
23-
// Bearing is the heading from the fighter to the contact, rounded to the nearest degree.
24-
Bearing() bearings.Bearing
25-
// Range is the distance from the fighter to the contact, rounded to the nearest nautical mile.
26-
Range() unit.Length
22+
Vector
2723
// Altitude of the contact above sea level, rounded to the nearest thousands of feet.
2824
Altitude() unit.Length
2925
// Altitude STACKS of the contact above sea level, rounded to the nearest thousands of feet.
3026
Stacks() []Stack
3127
}
3228

3329
type bra struct {
34-
bearing bearings.Bearing
35-
_range unit.Length
36-
stacks []Stack
30+
vector
31+
stacks []Stack
3732
}
3833

3934
// NewBRA creates a new [BRA].
@@ -42,22 +37,14 @@ func NewBRA(b bearings.Bearing, r unit.Length, a ...unit.Length) BRA {
4237
log.Warn().Stringer("bearing", b).Msg("bearing provided to NewBRA should be magnetic")
4338
}
4439
return &bra{
45-
bearing: b,
46-
_range: r,
47-
stacks: Stacks(a...),
40+
vector: vector{
41+
bearing: b,
42+
distance: r,
43+
},
44+
stacks: Stacks(a...),
4845
}
4946
}
5047

51-
// Bearing implements [BRA.Bearing].
52-
func (b *bra) Bearing() bearings.Bearing {
53-
return b.bearing
54-
}
55-
56-
// Range implements [BRA.Range].
57-
func (b *bra) Range() unit.Length {
58-
return unit.Length(math.Round(b._range.NauticalMiles())) * unit.NauticalMile
59-
}
60-
6148
// Altitude implements [BRA.Altitude].
6249
func (b *bra) Altitude() unit.Length {
6350
if len(b.stacks) == 0 {

pkg/brevity/bullseye.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package brevity
22

33
import (
44
"fmt"
5-
"math"
65

76
"github.com/dharmab/skyeye/pkg/bearings"
87
"github.com/martinlindhe/unit"
@@ -11,32 +10,38 @@ import (
1110

1211
// Bullseye is a magnetic bearing and distance from a reference point called the BULLSEYE.
1312
// Reference: ATP 3-52.4 Chapter IV section 4 subsection a.
14-
type Bullseye struct {
15-
bearing bearings.Bearing
16-
distance unit.Length
13+
type Bullseye interface {
14+
Bearing() bearings.Bearing
15+
Distance() unit.Length
16+
}
17+
18+
type bullseye struct {
19+
vector
1720
}
1821

1922
// NewBullseye creates a new [Bullseye].
20-
func NewBullseye(bearing bearings.Bearing, distance unit.Length) *Bullseye {
23+
func NewBullseye(bearing bearings.Bearing, distance unit.Length) Bullseye {
2124
if !bearing.IsMagnetic() {
2225
log.Warn().Stringer("bearing", bearing).Msg("bearing provided to NewBullseye should be magnetic")
2326
}
24-
return &Bullseye{
25-
bearing: bearing,
26-
distance: distance,
27+
return &bullseye{
28+
vector: vector{
29+
bearing: bearing,
30+
distance: distance,
31+
},
2732
}
2833
}
2934

3035
// Bearing from the BULLSEYE to the contact, rounded to the nearest degree.
31-
func (b *Bullseye) Bearing() bearings.Bearing {
32-
return b.bearing
36+
func (b *bullseye) Bearing() bearings.Bearing {
37+
return b.Bearing()
3338
}
3439

3540
// Distance from the BULLSEYE to the contact, rounded to the nearest nautical mile.
36-
func (b *Bullseye) Distance() unit.Length {
37-
return unit.Length(math.Round(b.distance.NauticalMiles())) * unit.NauticalMile
41+
func (b *bullseye) Distance() unit.Length {
42+
return b.Range()
3843
}
3944

40-
func (b *Bullseye) String() string {
41-
return fmt.Sprintf("%s/%.0f", b.bearing, b.distance.NauticalMiles())
45+
func (b *bullseye) String() string {
46+
return fmt.Sprintf("%s/%.0f", b.Bearing(), b.Distance().NauticalMiles())
4247
}

pkg/brevity/declare.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (r DeclareRequest) String() string {
7575
s += fmt.Sprintf(", altitude %.0f", r.Altitude.Feet())
7676
}
7777
} else {
78-
s += fmt.Sprintf("bullseye %s", &r.Bullseye)
78+
s += fmt.Sprintf("bullseye %s", r.Bullseye)
7979
}
8080
if r.Track != UnknownDirection {
8181
s += fmt.Sprintf(", track %s", r.Track)

pkg/brevity/group.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type Group interface {
1919
// Contacts is the number of contacts in the group.
2020
Contacts() int
2121
// Bullseye is the location of the group. This may be nil for BOGEY DOPE, SNAPLOCK, and THREAT calls.
22-
Bullseye() *Bullseye
22+
Bullseye() Bullseye
2323
// Altitude is the group's highest altitude. This may be zero for BOGEY DOPE, SNAPLOCK, and THREAT calls.
2424
Altitude() unit.Length
2525
// Stacks are the group's altitude STACKS, ordered from highest to lowest in intervals of at least 10,000 feet.

pkg/brevity/vector.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package brevity
2+
3+
import (
4+
"math"
5+
6+
"github.com/dharmab/skyeye/pkg/bearings"
7+
"github.com/martinlindhe/unit"
8+
)
9+
10+
type Vector interface {
11+
// Bearing is the heading from the fighter to the target location, rounded to the nearest degree.
12+
Bearing() bearings.Bearing
13+
// Range is the distance from the fighter to the target location, rounded to the nearest nautical mile.
14+
Range() unit.Length
15+
}
16+
17+
type vector struct {
18+
bearing bearings.Bearing
19+
distance unit.Length
20+
}
21+
22+
// Bearing implements [Vector.Bearing].
23+
func (v *vector) Bearing() bearings.Bearing {
24+
return v.bearing
25+
}
26+
27+
// Range implements [Vector.Range].
28+
func (v *vector) Range() unit.Length {
29+
return unit.Length(math.Round(v.distance.NauticalMiles())) * unit.NauticalMile
30+
}
31+
32+
type VectorRequest struct {
33+
// Callsign of the friendly aircraft requesting the vector.
34+
Callsign string
35+
// Location to which the friendly aircraft is requesting a vector.
36+
Location string
37+
}
38+
39+
func (r VectorRequest) String() string {
40+
return "VECTOR to " + r.Location + " for " + r.Callsign
41+
}
42+
43+
type VectorResponse struct {
44+
// Callsign of the friendly aircraft requesting the vector.
45+
Callsign string
46+
// Location which the friendly aircraft is requesting a vector.
47+
Location string
48+
// Contact is true if the callsign was correlated to an aircraft on frequency, otherwise false.
49+
Contact bool
50+
// Status is true if the vector was successfully computed, otherwise false.
51+
Status bool
52+
// Vector is the computed vector to the target location, if available.
53+
// // If Status is false, this may be nil.
54+
Vector Vector
55+
}

pkg/composer/faded.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func (c *Composer) ComposeFadedCall(call brevity.FadedCall) (response NaturalLan
1414
}
1515

1616
if bullseye := call.Group.Bullseye(); bullseye != nil {
17-
bullseye := c.composeBullseye(*bullseye)
17+
bullseye := c.composeBullseye(bullseye)
1818
response.WriteResponse(bullseye)
1919
}
2020

0 commit comments

Comments
 (0)