all: generate json, not code
This includes modifying horsebot to use the generated JSON, as well as moving the generator to another cmd/ directory. Remove the generated code while we're here. Koka tests still have to be updated, but it requires a JSON parser.
This commit is contained in:
@@ -3,6 +3,8 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -20,11 +22,14 @@ import (
|
||||
"github.com/disgoorg/disgo/rest"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse/global"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
// data options
|
||||
skillsFile string
|
||||
skillGroupsFile string
|
||||
// discord bot options
|
||||
tokenFile string
|
||||
// http api options
|
||||
addr string
|
||||
@@ -34,6 +39,8 @@ func main() {
|
||||
level slog.Level
|
||||
textfmt string
|
||||
)
|
||||
flag.StringVar(&skillsFile, "skills", "", "json `file` containing skill data")
|
||||
flag.StringVar(&skillGroupsFile, "skill-groups", "", "json `file` containing skill group data")
|
||||
flag.StringVar(&tokenFile, "token", "", "`file` containing the Discord bot token")
|
||||
flag.StringVar(&addr, "http", "", "`address` to bind HTTP API server")
|
||||
flag.StringVar(&route, "route", "/interactions/callback", "`path` to serve HTTP API calls")
|
||||
@@ -54,6 +61,14 @@ func main() {
|
||||
}
|
||||
slog.SetDefault(slog.New(lh))
|
||||
|
||||
byID, byName, err := loadSkills(skillsFile)
|
||||
groups, err2 := loadSkillGroups(skillGroupsFile)
|
||||
if err = errors.Join(err, err2); err != nil {
|
||||
slog.Error("loading data", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
skillsByID, skillsByName, skillGroupMap = byID, byName, groups
|
||||
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
@@ -133,16 +148,59 @@ var commands = []discord.ApplicationCommandCreate{
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(zeph): these globals could go away, but there's a bit of ceremony to doing that
|
||||
var (
|
||||
skillsByID map[horse.SkillID]horse.Skill
|
||||
skillsByName map[string]horse.SkillID
|
||||
skillGroupMap map[horse.SkillGroupID]horse.SkillGroup
|
||||
)
|
||||
|
||||
func loadSkills(file string) (map[horse.SkillID]horse.Skill, map[string]horse.SkillID, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var skills []horse.Skill
|
||||
if err := json.Unmarshal(b, &skills); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
byID := make(map[horse.SkillID]horse.Skill, len(skills))
|
||||
byName := make(map[string]horse.SkillID, len(skills))
|
||||
for _, s := range skills {
|
||||
byID[s.ID] = s
|
||||
byName[s.Name] = s.ID
|
||||
}
|
||||
slog.Info("loaded skills", slog.Int("count", len(skills)))
|
||||
return byID, byName, nil
|
||||
}
|
||||
|
||||
func loadSkillGroups(file string) (map[horse.SkillGroupID]horse.SkillGroup, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var groups []horse.SkillGroup
|
||||
if err := json.Unmarshal(b, &groups); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[horse.SkillGroupID]horse.SkillGroup, len(groups))
|
||||
for _, s := range groups {
|
||||
m[s.ID] = s
|
||||
}
|
||||
slog.Info("loaded skill groups", slog.Int("count", len(groups)))
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func skillHandler(data discord.SlashCommandInteractionData, e *handler.CommandEvent) error {
|
||||
q := data.String("query")
|
||||
id, err := strconv.ParseInt(q, 10, 32)
|
||||
if err == nil {
|
||||
// note inverted condition; this is when we have an id
|
||||
id = int64(global.AllSkills[horse.SkillID(id)].ID)
|
||||
id = int64(skillsByID[horse.SkillID(id)].ID)
|
||||
}
|
||||
if id == 0 {
|
||||
// Either we weren't given a number or the number doesn't match any skill ID.
|
||||
v := global.SkillNameToID[q]
|
||||
v := skillsByName[q]
|
||||
if v == 0 {
|
||||
// No such skill.
|
||||
m := discord.MessageCreate{
|
||||
@@ -155,7 +213,7 @@ func skillHandler(data discord.SlashCommandInteractionData, e *handler.CommandEv
|
||||
}
|
||||
// TODO(zeph): search conditions and effects, give a list
|
||||
m := discord.MessageCreate{
|
||||
Components: []discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
Components: []discord.LayoutComponent{RenderSkill(horse.SkillID(id), skillsByID, skillGroupMap)},
|
||||
Flags: discord.MessageFlagIsComponentsV2,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
@@ -177,7 +235,7 @@ func skillButton(data discord.ButtonInteractionData, e *handler.ComponentEvent)
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
m := discord.MessageUpdate{
|
||||
Components: &[]discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
Components: &[]discord.LayoutComponent{RenderSkill(horse.SkillID(id), skillsByID, skillGroupMap)},
|
||||
}
|
||||
return e.UpdateMessage(m)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/cmd/horsebot/autocomplete"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse/global"
|
||||
)
|
||||
|
||||
func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map[horse.SkillGroupID][4]horse.SkillID) discord.ContainerComponent {
|
||||
func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map[horse.SkillGroupID]horse.SkillGroup) discord.ContainerComponent {
|
||||
s, ok := all[id]
|
||||
if !ok {
|
||||
return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to RenderSkill", id))
|
||||
@@ -95,7 +94,8 @@ func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map
|
||||
l := discord.NewTextDisplayf("%s ・ SP cost %d ・ Grade value %d ・ [Conditions on GameTora](https://gametora.com/umamusume/skill-condition-viewer?skill=%d)", skilltype, s.SPCost, s.GradeValue, s.ID)
|
||||
r.Components = append(r.Components, discord.NewSmallSeparator(), l)
|
||||
rel := make([]horse.Skill, 0, 4)
|
||||
for _, id := range groups[s.Group] {
|
||||
group := groups[s.Group]
|
||||
for _, id := range [...]horse.SkillID{group.Skill1, group.Skill2, group.Skill3, group.SkillBad} {
|
||||
if id != 0 {
|
||||
rel = append(rel, all[id])
|
||||
}
|
||||
@@ -135,8 +135,8 @@ func isDebuff(s horse.Skill) bool {
|
||||
|
||||
var skillGlobalAuto = sync.OnceValue(func() *autocomplete.Set[discord.AutocompleteChoice] {
|
||||
var set autocomplete.Set[discord.AutocompleteChoice]
|
||||
for _, id := range global.OrderedSkills {
|
||||
s := global.AllSkills[id]
|
||||
// NOTE(zeph): we're using global variables here
|
||||
for _, s := range skillsByID {
|
||||
set.Add(s.Name, discord.AutocompleteChoiceString{Name: s.Name, Value: s.Name})
|
||||
if s.UniqueOwner != "" {
|
||||
if s.Rarity >= 3 {
|
||||
|
||||
Reference in New Issue
Block a user