195 lines
5.0 KiB
Go
195 lines
5.0 KiB
Go
package controller
|
|
|
|
import (
|
|
"fmt"
|
|
"iter"
|
|
"slices"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/iliadenisov/galaxy/internal/model/game"
|
|
)
|
|
|
|
type Cache struct {
|
|
g *game.Game
|
|
cacheRaceIndexByID map[uuid.UUID]int
|
|
raceIndexByShipGroupIndex map[int]int
|
|
shipClassByShipGroupIndex map[int]*game.ShipType
|
|
planetByPlanetNumber map[uint]*game.Planet
|
|
cacheRelation map[int]map[int]game.Relation
|
|
}
|
|
|
|
func NewCache(g *game.Game) *Cache {
|
|
if g == nil {
|
|
panic("NewCache: nil Game passed")
|
|
}
|
|
c := &Cache{
|
|
g: g,
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (c *Cache) Relation(r1, r2 int) game.Relation {
|
|
if c.cacheRelation == nil {
|
|
for r1 := range c.g.Race {
|
|
for r2 := range c.g.Race {
|
|
if r1 == r2 {
|
|
continue
|
|
}
|
|
rel := slices.IndexFunc(c.g.Race[r1].Relations, func(r game.RaceRelation) bool { return r.RaceID == c.g.Race[r2].ID })
|
|
if rel < 0 {
|
|
panic(fmt.Sprintf("Relation: opponent not found idx=%d", r2))
|
|
}
|
|
if _, ok := c.cacheRelation[r1]; !ok {
|
|
c.cacheRelation[r1] = make(map[int]game.Relation)
|
|
}
|
|
c.cacheRelation[r1][r2] = c.g.Race[r1].Relations[rel].Relation
|
|
}
|
|
}
|
|
|
|
}
|
|
if _, ok := c.cacheRelation[r1]; !ok {
|
|
panic(fmt.Sprintf("Relation: no left race idx=%d", r1))
|
|
}
|
|
if v, ok := c.cacheRelation[r1][r2]; !ok {
|
|
panic(fmt.Sprintf("Relation: no right race idx=%d", r2))
|
|
} else {
|
|
return v
|
|
}
|
|
}
|
|
|
|
func (c *Cache) Planet(planetNumber uint) *game.Planet {
|
|
if c.planetByPlanetNumber == nil {
|
|
c.planetByPlanetNumber = make(map[uint]*game.Planet)
|
|
for p := range c.g.Map.Planet {
|
|
c.planetByPlanetNumber[c.g.Map.Planet[p].Number] = &c.g.Map.Planet[p]
|
|
}
|
|
}
|
|
if v, ok := c.planetByPlanetNumber[planetNumber]; ok {
|
|
return v
|
|
} else {
|
|
panic(fmt.Sprintf("Planet: not found by number=%d", planetNumber))
|
|
}
|
|
}
|
|
|
|
func (c *Cache) ShipGroupShipClass(groupIndex int) *game.ShipType {
|
|
if c.shipClassByShipGroupIndex == nil {
|
|
c.fillShipsAndGroups()
|
|
}
|
|
c.validateShipGroupIndex(groupIndex)
|
|
if v, ok := c.shipClassByShipGroupIndex[groupIndex]; ok {
|
|
return v
|
|
} else {
|
|
panic(fmt.Sprintf("ShipClassByShipGroupIndex: group not found by index=%v", groupIndex))
|
|
}
|
|
}
|
|
|
|
func (c *Cache) RaceIndex(ID uuid.UUID) int {
|
|
if c.cacheRaceIndexByID == nil {
|
|
c.cacheRaceIndexByID = make(map[uuid.UUID]int)
|
|
for i := range c.g.Race {
|
|
c.cacheRaceIndexByID[c.g.Race[i].ID] = i
|
|
}
|
|
}
|
|
if v, ok := c.cacheRaceIndexByID[ID]; ok {
|
|
return v
|
|
} else {
|
|
panic(fmt.Sprintf("RaceIndex: race not found by ID=%v", ID))
|
|
}
|
|
}
|
|
|
|
// ShipGroup is a proxy func, nothing to cache
|
|
func (c *Cache) ShipGroup(groupIndex int) *game.ShipGroup {
|
|
c.validateShipGroupIndex(groupIndex)
|
|
return &c.g.ShipGroups[groupIndex]
|
|
}
|
|
|
|
func (c *Cache) ShipGroupsIndex() iter.Seq[int] {
|
|
return func(yield func(int) bool) {
|
|
for i := range c.g.ShipGroups {
|
|
if !yield(i) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Cache) ShipGroupOwnerRaceIndex(groupIndex int) int {
|
|
if c.raceIndexByShipGroupIndex == nil {
|
|
c.fillShipsAndGroups()
|
|
}
|
|
c.validateShipGroupIndex(groupIndex)
|
|
if v, ok := c.raceIndexByShipGroupIndex[groupIndex]; ok {
|
|
return v
|
|
} else {
|
|
panic(fmt.Sprintf("ShipGroupRace: group not found by index=%v", groupIndex))
|
|
}
|
|
}
|
|
|
|
func (c *Cache) ShipGroupOwnerRace(groupIndex int) *game.Race {
|
|
return &c.g.Race[c.ShipGroupOwnerRaceIndex(groupIndex)]
|
|
}
|
|
|
|
func (c *Cache) ShipGroupNumber(i int, n uint) {
|
|
c.validateShipGroupIndex(i)
|
|
c.g.ShipGroups[i].Number = n
|
|
}
|
|
|
|
func (c *Cache) DeleteShipGroup(i int) {
|
|
c.validateShipGroupIndex(i)
|
|
c.unsafeDeleteShipGroup(i)
|
|
}
|
|
|
|
func (c *Cache) DeleteKilledShipGroups() {
|
|
for i := len(c.g.ShipGroups) - 1; i >= 0; i-- {
|
|
if c.g.ShipGroups[i].Number == 0 {
|
|
c.unsafeDeleteShipGroup(i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Cache) unsafeDeleteShipGroup(i int) {
|
|
c.g.ShipGroups = append(c.g.ShipGroups[:i], c.g.ShipGroups[i+1:]...)
|
|
delete(c.raceIndexByShipGroupIndex, i)
|
|
delete(c.shipClassByShipGroupIndex, i)
|
|
}
|
|
|
|
// Internal
|
|
|
|
func (c *Cache) validateShipGroupIndex(i int) {
|
|
if i >= len(c.g.ShipGroups) {
|
|
panic(fmt.Sprintf("group index out of groups len: %d >= %d", i, len(c.g.ShipGroups)))
|
|
}
|
|
}
|
|
|
|
func (c *Cache) fillShipsAndGroups() {
|
|
if c.raceIndexByShipGroupIndex != nil {
|
|
clear(c.raceIndexByShipGroupIndex)
|
|
} else {
|
|
c.raceIndexByShipGroupIndex = make(map[int]int)
|
|
}
|
|
if c.shipClassByShipGroupIndex != nil {
|
|
clear(c.shipClassByShipGroupIndex)
|
|
} else {
|
|
c.shipClassByShipGroupIndex = make(map[int]*game.ShipType)
|
|
}
|
|
for groupIndex := range c.g.ShipGroups {
|
|
ri := c.RaceIndex(c.g.ShipGroups[groupIndex].OwnerID)
|
|
c.raceIndexByShipGroupIndex[groupIndex] = ri
|
|
sti, ok := ShipClassIndex(c.g, ri, c.g.ShipGroups[groupIndex].TypeID)
|
|
if !ok {
|
|
panic(fmt.Sprintf("CollectPlanetGroups: ship class not found for race=%q group=%v", c.g.Race[ri].Name, c.g.ShipGroups[groupIndex].Index))
|
|
}
|
|
c.shipClassByShipGroupIndex[groupIndex] = &c.g.Race[ri].ShipTypes[sti]
|
|
}
|
|
}
|
|
|
|
// Helpers
|
|
|
|
func ShipClassIndex(g *game.Game, ri int, classID uuid.UUID) (int, bool) {
|
|
if len(g.Race) < ri+1 {
|
|
panic(fmt.Sprintf("ShipClass: game race index %d invalid: len=%d", ri, len(g.Race)))
|
|
}
|
|
sti := slices.IndexFunc(g.Race[ri].ShipTypes, func(st game.ShipType) bool { return st.ID == classID })
|
|
return sti, sti >= 0
|
|
}
|