From 41eed9292964c39aaa46c1e4fa60a9c1894c3904 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Wed, 27 Aug 2025 10:54:55 -0500 Subject: [PATCH] clean up helpers package, remove orderedmaps and clean up list generation --- data/control.json | 11 ++++++++ data/dk.db | Bin 94208 -> 94208 bytes go.mod | 2 +- internal/components/asides.go | 25 ++++++------------ internal/helpers/exp/exp.go | 5 ---- internal/helpers/http.go | 10 ------- internal/helpers/math.go | 5 ++++ internal/helpers/ordered_map.go | 36 -------------------------- internal/models/spells/spells.go | 15 +++++++++-- internal/models/towns/towns.go | 25 +++++++++++++++--- internal/models/users/users.go | 28 +++++++++++++++++--- internal/routes/town.go | 43 +++++-------------------------- main.go | 5 ++++ templates/leftside.html | 4 ++- templates/rightside.html | 4 +-- 15 files changed, 99 insertions(+), 119 deletions(-) create mode 100644 data/control.json delete mode 100644 internal/helpers/exp/exp.go delete mode 100644 internal/helpers/http.go delete mode 100644 internal/helpers/ordered_map.go diff --git a/data/control.json b/data/control.json new file mode 100644 index 0000000..8ea3c81 --- /dev/null +++ b/data/control.json @@ -0,0 +1,11 @@ +{ + "world_size": 200, + "open": 1, + "admin_email": "", + "email_mode": "file", + "email_file_path": "data/emails.txt", + "smtp_host": "", + "smtp_port": "587", + "smtp_username": "", + "smtp_password": "" +} \ No newline at end of file diff --git a/data/dk.db b/data/dk.db index 0fe9890b9bd836b8d91886576eb574f616ced542..19f144262e6326124711ec8f5978de76ec63b4a3 100644 GIT binary patch delta 331 zcmZp8z}oPDbpxY;B>#E_PX0~?{ulf=`7iMAXoLtP3oM3)20|Nus=FRqj6F8XoN*MU{`ARkm3S{ur zH(D_1G6*;NYjW_iuyAs4FiLYUf&nKZ2apFMz0${n-A9reA+RdUUf^^+~j!`&*~vkHqU zBGR)n{f+c(Jd+FbGfk6?B8&_z3Ua(E3X%&99CK3h9f~s&i?Xxz@={AO*2`*wFpFoN zLP&mj9zQ=95T&rPPS(G_oO!*h_~x7UwHr8?_`fjl|Kk4w43!uBJSu(kmP~vB93}l?Fe}6giT0M=; bH}7jV040Ah@c#mu_MV@efrXKolTic!Rxczi diff --git a/go.mod b/go.mod index e8c677a..4f137f0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.25.0 require ( git.sharkk.net/Sharkk/Sashimi v1.1.4 git.sharkk.net/Sharkk/Sushi v1.2.0 - github.com/valyala/fasthttp v1.65.0 ) require ( @@ -17,6 +16,7 @@ require ( github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.65.0 // indirect golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/sys v0.35.0 // indirect diff --git a/internal/components/asides.go b/internal/components/asides.go index 0634112..829322b 100644 --- a/internal/components/asides.go +++ b/internal/components/asides.go @@ -25,15 +25,11 @@ func LeftAside(ctx sushi.Ctx) map[string]any { } // Build owned town maps list - if user.Towns != "" { - townMap := helpers.NewOrderedMap[int, *towns.Town]() - for _, id := range user.GetTownIDs() { - if town, err := towns.Find(id); err == nil { - townMap.Set(id, town) - } - } - data["_towns"] = townMap.ToSlice() + townList, err := user.GetKnownTowns() + if err != nil { + fmt.Printf("User town list error: %s\n", err.Error()) } + data["_towns"] = townList return data } @@ -65,16 +61,11 @@ func RightAside(ctx sushi.Ctx) map[string]any { } // Build known healing spells list - userSpells, err := user.GetSpells() - if err == nil { - spellMap := helpers.NewOrderedMap[int, string]() - for _, spell := range userSpells { - if spell.IsHeal() { - spellMap.Set(spell.ID, spell.Name) - } - } - data["_spells"] = spellMap.ToSlice() + healingSpells, err := user.GetHealingSpells() + if err != nil { + fmt.Printf("User healing spells list error: %s\n", err.Error()) } + data["_spells"] = healingSpells return data } diff --git a/internal/helpers/exp/exp.go b/internal/helpers/exp/exp.go deleted file mode 100644 index aa52d4b..0000000 --- a/internal/helpers/exp/exp.go +++ /dev/null @@ -1,5 +0,0 @@ -package exp - -func Calc(level int) int { - return level * level * level -} diff --git a/internal/helpers/http.go b/internal/helpers/http.go deleted file mode 100644 index ea1b305..0000000 --- a/internal/helpers/http.go +++ /dev/null @@ -1,10 +0,0 @@ -package helpers - -import "github.com/valyala/fasthttp" - -// IsHTTPS tries to determine if the current request context is over HTTPS -func IsHTTPS(ctx *fasthttp.RequestCtx) bool { - return ctx.IsTLS() || - string(ctx.Request.Header.Peek("X-Forwarded-Proto")) == "https" || - string(ctx.Request.Header.Peek("X-Forwarded-Scheme")) == "https" -} diff --git a/internal/helpers/math.go b/internal/helpers/math.go index 564cc9a..36da015 100644 --- a/internal/helpers/math.go +++ b/internal/helpers/math.go @@ -8,3 +8,8 @@ func ClampPct(num, denom, minimum, maximum float64) float64 { } return max(minimum, min(maximum, (num/denom)*100)) } + +// ExpAtLevel calculates the needed total EXP for the given level. +func ExpAtLevel(level int) int { + return level * level * level +} diff --git a/internal/helpers/ordered_map.go b/internal/helpers/ordered_map.go deleted file mode 100644 index 13f00c0..0000000 --- a/internal/helpers/ordered_map.go +++ /dev/null @@ -1,36 +0,0 @@ -package helpers - -type OrderedMap[K comparable, V any] struct { - keys []K - data map[K]V -} - -func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] { - return &OrderedMap[K, V]{ - keys: make([]K, 0), - data: make(map[K]V), - } -} - -func (om *OrderedMap[K, V]) Set(key K, value V) { - if _, exists := om.data[key]; !exists { - om.keys = append(om.keys, key) - } - om.data[key] = value -} - -func (om *OrderedMap[K, V]) Range(fn func(K, V) bool) { - for _, key := range om.keys { - if !fn(key, om.data[key]) { - break - } - } -} - -func (om *OrderedMap[K, V]) ToSlice() []V { - result := make([]V, 0, len(om.keys)) - for _, key := range om.keys { - result = append(result, om.data[key]) - } - return result -} diff --git a/internal/models/spells/spells.go b/internal/models/spells/spells.go index c95bb35..c999877 100644 --- a/internal/models/spells/spells.go +++ b/internal/models/spells/spells.go @@ -116,8 +116,8 @@ func ByName(name string) (*Spell, error) { func UnlocksForClassAtLevel(classID, level int) ([]*Spell, error) { var spells []*Spell query := ` - SELECT s.* FROM spells s - JOIN spell_unlocks u ON s.id = u.spell_id + SELECT s.* FROM spells s + JOIN spell_unlocks u ON s.id = u.spell_id WHERE u.class_id = %d AND u.level = %d ORDER BY s.type ASC, s.mp ASC, s.id ASC` err := database.Select(&spells, query, classID, level) @@ -135,6 +135,17 @@ func UserSpells(userID int) ([]*Spell, error) { return spells, err } +func UserHealingSpells(userID int) ([]*Spell, error) { + var spells []*Spell + query := ` + SELECT s.* FROM spells s + JOIN user_spells us ON s.id = us.spell_id + WHERE us.user_id = %d AND s.type = 0 + ORDER BY s.mp ASC, s.id ASC` + err := database.Select(&spells, query, userID) + return spells, err +} + func GrantSpell(userID, spellID int) error { return database.Exec("INSERT OR IGNORE INTO user_spells (user_id, spell_id) VALUES (%d, %d)", userID, spellID) } diff --git a/internal/models/towns/towns.go b/internal/models/towns/towns.go index b5906c1..e4b8451 100644 --- a/internal/models/towns/towns.go +++ b/internal/models/towns/towns.go @@ -8,6 +8,7 @@ import ( "dk/internal/database" "dk/internal/helpers" + "dk/internal/models/items" ) // Town represents a town in the game @@ -142,16 +143,16 @@ func ByDistance(fromX, fromY, maxDistance int) ([]*Town, error) { } // Helper methods -func (t *Town) GetShopItems() []int { +func (t *Town) GetShopItemIDs() []int { return helpers.StringToInts(t.ShopList) } -func (t *Town) SetShopItems(items []int) { +func (t *Town) SetShopItemIDs(items []int) { t.ShopList = helpers.IntsToString(items) } func (t *Town) HasShopItem(itemID int) bool { - return slices.Contains(t.GetShopItems(), itemID) + return slices.Contains(t.GetShopItemIDs(), itemID) } func (t *Town) DistanceFromSquared(x, y int) float64 { @@ -181,7 +182,7 @@ func (t *Town) CanAffordTeleport(gold int) bool { } func (t *Town) HasShop() bool { - return len(t.GetShopItems()) > 0 + return len(t.GetShopItemIDs()) > 0 } func (t *Town) GetPosition() (int, int) { @@ -192,3 +193,19 @@ func (t *Town) SetPosition(x, y int) { t.X = x t.Y = y } + +func (t *Town) GetShopItems() ([]*items.Item, error) { + itemIDs := t.GetShopItemIDs() + result := make([]*items.Item, 0, len(itemIDs)) + + for _, itemID := range itemIDs { + item, err := items.Find(itemID) + if err != nil { + // Skip invalid item IDs rather than failing entirely + continue + } + result = append(result, item) + } + + return result, nil +} diff --git a/internal/models/users/users.go b/internal/models/users/users.go index ef98367..93b55c2 100644 --- a/internal/models/users/users.go +++ b/internal/models/users/users.go @@ -8,9 +8,9 @@ import ( "dk/internal/database" "dk/internal/helpers" - "dk/internal/helpers/exp" "dk/internal/models/classes" "dk/internal/models/spells" + "dk/internal/models/towns" ) // User represents a user in the game @@ -213,6 +213,10 @@ func (u *User) GetSpells() ([]*spells.Spell, error) { return spells.UserSpells(u.ID) } +func (u *User) GetHealingSpells() ([]*spells.Spell, error) { + return spells.UserHealingSpells(u.ID) +} + func (u *User) HasSpell(spellID int) bool { return spells.HasSpell(u.ID, spellID) } @@ -288,7 +292,7 @@ func (u *User) SetPosition(x, y int) { } func (u *User) ExpNeededForNextLevel() int { - return exp.Calc(u.Level + 1) + return helpers.ExpAtLevel(u.Level + 1) } func (u *User) GrantExp(expAmount int) map[string]any { @@ -324,7 +328,7 @@ func (u *User) CalculateLevelUp(expGain int) (newLevel, newStr, newDex, newExp i totalExp := u.Exp + expGain for { - expNeeded := exp.Calc(level + 1) + expNeeded := helpers.ExpAtLevel(level + 1) if totalExp < expNeeded { break } @@ -343,7 +347,7 @@ func (u *User) ExpProgress() float64 { return float64(u.Exp) / float64(u.ExpNeededForNextLevel()) * 100 } - currentLevelExp := exp.Calc(u.Level) + currentLevelExp := helpers.ExpAtLevel(u.Level) nextLevelExp := u.ExpNeededForNextLevel() progressExp := u.Exp @@ -375,3 +379,19 @@ func (u *User) learnSpellsForLevel(level int) error { return u.GrantSpells(spellIDs) } + +func (u *User) GetKnownTowns() ([]*towns.Town, error) { + townIDs := u.GetTownIDs() + result := make([]*towns.Town, 0, len(townIDs)) + + for _, townID := range townIDs { + town, err := towns.Find(townID) + if err != nil { + // Skip invalid town IDs rather than failing entirely + continue + } + result = append(result, town) + } + + return result, nil +} diff --git a/internal/routes/town.go b/internal/routes/town.go index 36bb31b..3bd95a8 100644 --- a/internal/routes/town.go +++ b/internal/routes/town.go @@ -9,7 +9,6 @@ import ( "dk/internal/models/towns" "dk/internal/models/users" "fmt" - "slices" sushi "git.sharkk.net/Sharkk/Sushi" "git.sharkk.net/Sharkk/Sushi/auth" @@ -131,20 +130,14 @@ func showShop(ctx sushi.Ctx) { town := ctx.UserValue("town").(*towns.Town) - var itemlist []*items.Item - if town.ShopList != "" { - itemMap := helpers.NewOrderedMap[int, *items.Item]() - for _, id := range town.GetShopItems() { - if item, err := items.Find(id); err == nil { - itemMap.Set(id, item) - } - } - itemlist = itemMap.ToSlice() + itemList, err := town.GetShopItems() + if err != nil { + fmt.Printf("Town shop list error: %s\n", err.Error()) } components.RenderPage(ctx, town.Name+" Shop", "town/shop.html", map[string]any{ "town": town, - "itemlist": itemlist, + "itemlist": itemList, "error_message": errorHTML, }) } @@ -155,7 +148,7 @@ func buyItem(ctx sushi.Ctx) { id := ctx.Param("id").Int() town := ctx.UserValue("town").(*towns.Town) - if !slices.Contains(town.GetShopItems(), id) { + if !town.HasShopItem(id) { sess.SetFlash("error", "The item doesn't exist in this shop.") ctx.Redirect("/town/shop") return @@ -216,36 +209,12 @@ func showMaps(ctx sushi.Ctx) { } town := ctx.UserValue("town").(*towns.Town) - user := ctx.GetCurrentUser().(*users.User) - maplist := helpers.NewOrderedMap[int, Map]() towns, _ := towns.All() - var mapped []int - if user.Towns != "" { - mapped = user.GetTownIDs() - } - for _, town := range towns { - var owned bool - if mapped != nil && slices.Contains(mapped, town.ID) { - owned = true - } else { - owned = false - } - - maplist.Set(town.ID, Map{ - ID: town.ID, - Name: town.Name, - Cost: town.MapCost, - Owned: owned, - X: town.X, - Y: town.Y, - TP: town.TPCost, - }) - } components.RenderPage(ctx, town.Name+" Maps", "town/maps.html", map[string]any{ "town": town, - "maplist": maplist.ToSlice(), + "towns": towns, "error_message": errorHTML, }) } diff --git a/main.go b/main.go index 9cdc5ca..f8870db 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "dk/internal/control" "dk/internal/database" + "dk/internal/helpers/email" "dk/internal/helpers/markdown" "dk/internal/models/users" "dk/internal/routes" @@ -142,10 +143,14 @@ func start(port string) error { control.Init(filepath.Join(cwd, "data/control.json")) defer control.Save() + controls := control.Get() template.InitializeCache(cwd) template.RegisterFunc("md", markdown.MarkdownTemplateFunc) + email.Init(controls.EmailMode, controls.EmailFilePath, + controls.SMTPHost, controls.SMTPPort, controls.SMTPUsername, controls.SMTPPassword) + authMW := auth.New(getUserByID) app := sushi.New() diff --git a/templates/leftside.html b/templates/leftside.html index de1871c..e9a1014 100644 --- a/templates/leftside.html +++ b/templates/leftside.html @@ -29,15 +29,17 @@
Town Maps
{if #_towns > 0} {for t in _towns} + {if user.HasTownMap(t.ID)} {if town != nil and t.Name == town.Name} {t.Name} (here) {else} {if user.TP < t.TPCost} {t.Name} {else} - {t.Name} + {t.Name} {/if} {/if} + {/if} {/for} {else} No town maps diff --git a/templates/rightside.html b/templates/rightside.html index 772239e..400154c 100644 --- a/templates/rightside.html +++ b/templates/rightside.html @@ -76,8 +76,8 @@
Spells
{if #_spells > 0} - {for id,name in _spells} - {name} + {for spell in _spells} + {spell.Name} {/for} {else} No known healing spells