177 lines
3.9 KiB
Go
177 lines
3.9 KiB
Go
|
package modlist
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"os"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/charmbracelet/log"
|
||
|
)
|
||
|
|
||
|
// fileRegex matches
|
||
|
const fileRegex string = "([\\w-]+)_([0-9.]+).zip"
|
||
|
|
||
|
/// Modlist types and related functions.
|
||
|
|
||
|
// Mod holds data about a single mod.
|
||
|
type Mod struct {
|
||
|
Name string `json:"name"`
|
||
|
Enabled bool `json:"enabled"`
|
||
|
}
|
||
|
|
||
|
// Modlist holds a slice of mods.
|
||
|
type Modlist struct {
|
||
|
Mods []Mod `json:"mods"`
|
||
|
}
|
||
|
|
||
|
/// Non exported functions
|
||
|
|
||
|
func (modlist *Modlist) setModStatus(name string, status bool) {
|
||
|
for i := range modlist.Mods {
|
||
|
if modlist.Mods[i].Name == name && modlist.Mods[i].Enabled != status {
|
||
|
modlist.Mods[i].Enabled = status
|
||
|
log.Debugf("Setting status of mod %s to %v", modlist.Mods[i].Name, modlist.Mods[i].Enabled)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (modlist *Modlist) setAllStatus(status bool) {
|
||
|
for i := range modlist.Mods {
|
||
|
modlist.Mods[i].Enabled = status
|
||
|
log.Debugf("Setting status of mod %s to %v", modlist.Mods[i].Name, modlist.Mods[i].Enabled)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EnableMod enables the given mod.
|
||
|
func (modlist *Modlist) EnableMod(name string) {
|
||
|
modlist.setModStatus(name, true)
|
||
|
}
|
||
|
|
||
|
// EnableMods enables the given mods.
|
||
|
func (modlist *Modlist) EnableMods(names ...string) {
|
||
|
for _, name := range names {
|
||
|
modlist.EnableMod(name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DisableMod disables the given mod.
|
||
|
func (modlist *Modlist) DisableMod(name string) {
|
||
|
modlist.setModStatus(name, false)
|
||
|
}
|
||
|
|
||
|
// DisableMods disables the given mods.
|
||
|
func (modlist *Modlist) DisableMods(names ...string) {
|
||
|
for _, name := range names {
|
||
|
modlist.DisableMod(name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EnableAll enables all mods.
|
||
|
func (modlist *Modlist) EnableAll() {
|
||
|
modlist.setAllStatus(true)
|
||
|
}
|
||
|
|
||
|
// DisableAll disables all mods.
|
||
|
func (modlist *Modlist) DisableAll() {
|
||
|
modlist.setAllStatus(false)
|
||
|
}
|
||
|
|
||
|
// HasMod reports if a modlist has a mod with name `s`
|
||
|
func (modlist *Modlist) HasMod(s string) bool {
|
||
|
for _, mod := range modlist.Mods {
|
||
|
if mod.Name == s {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// HasMod reports if a modlist has an enabled mod with name `s`
|
||
|
func (modlist *Modlist) HasModEnabled(s string) bool {
|
||
|
for _, mod := range modlist.Mods {
|
||
|
if mod.Name == s && mod.Enabled {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Print out each mod and its status.
|
||
|
func (modlist *Modlist) Print(prefix string) {
|
||
|
log.Info(prefix + ": {")
|
||
|
for _, mod := range modlist.Mods {
|
||
|
var endis string
|
||
|
// I wish go had a ternary so this could all be in one line
|
||
|
if mod.Enabled {
|
||
|
endis = "en"
|
||
|
} else {
|
||
|
endis = "dis"
|
||
|
}
|
||
|
log.Infof("\t%s: %sabled,", mod.Name, endis)
|
||
|
}
|
||
|
log.Info("}")
|
||
|
}
|
||
|
|
||
|
func (modlist *Modlist) String() {
|
||
|
modlist.Print("mods")
|
||
|
}
|
||
|
|
||
|
/// Functions related to the modlist but that shouldn't be attached to the types
|
||
|
|
||
|
// WriteToFile writes the modlist to the given filename.
|
||
|
func WriteToFile(filename string, mods *Modlist) error {
|
||
|
data, err := json.MarshalIndent(&mods, "", " ")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
os.WriteFile(filename, data, os.FileMode(0744))
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// ReadFromFile reads the modlist from the given filename.
|
||
|
func ReadFromFile(filename string) (Modlist, error) {
|
||
|
var mods Modlist = Modlist{}
|
||
|
|
||
|
data, err := os.ReadFile(filename)
|
||
|
if err != nil {
|
||
|
return Modlist{}, err
|
||
|
}
|
||
|
|
||
|
err = json.Unmarshal(data, &mods)
|
||
|
if err != nil {
|
||
|
return Modlist{}, err
|
||
|
}
|
||
|
|
||
|
return mods, nil
|
||
|
}
|
||
|
|
||
|
// AddModsNotInList finds mod archives in the mod folder that aren't in the modlist, and adds them.
|
||
|
func AddModsNotInList(modsdir string, mods *Modlist) error {
|
||
|
r := regexp.MustCompile(fileRegex)
|
||
|
|
||
|
files, err := os.ReadDir(modsdir)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for _, file := range files {
|
||
|
if strings.HasSuffix(file.Name(), ".zip") && !file.IsDir() {
|
||
|
groups := r.FindAllStringSubmatch(file.Name(), -1)
|
||
|
name := groups[0][1]
|
||
|
version := groups[0][2]
|
||
|
|
||
|
if !mods.HasMod(name) {
|
||
|
log.Printf("%s isn't enabled, adding v%s in disabled state.", name, version)
|
||
|
mods.Mods = append(mods.Mods, Mod{
|
||
|
Name: name,
|
||
|
Enabled: false,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|