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:
2026-03-08 21:33:46 -04:00
parent 7ff271ff2d
commit 8632bb8c3c
60 changed files with 71 additions and 62322 deletions

View File

@@ -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)
}