- Added a new AGENTS.md file to document the project structure and conventions. - Updated .gitignore to include node_modules and refined cursor rules. - Introduced new backend and frontend components for improved map interactions, including context menus and controls. - Enhanced API composables for better admin and authentication functionalities. - Refactored existing components for cleaner code and improved user experience. - Updated README.md to clarify production asset serving and user setup instructions.
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/andyleap/hnh-map/internal/app/store"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
func (a *App) updatePositions(rw http.ResponseWriter, req *http.Request) {
|
|
defer req.Body.Close()
|
|
craws := map[string]struct {
|
|
Name string
|
|
GridID string
|
|
Coords struct {
|
|
X, Y int
|
|
}
|
|
Type string
|
|
}{}
|
|
buf, err := io.ReadAll(req.Body)
|
|
if err != nil {
|
|
log.Println("Error reading position update json: ", err)
|
|
return
|
|
}
|
|
err = json.Unmarshal(buf, &craws)
|
|
if err != nil {
|
|
log.Println("Error decoding position update json: ", err)
|
|
log.Println("Original json: ", string(buf))
|
|
return
|
|
}
|
|
// Read grid data first (inside db.View), then update characters (with chmu only).
|
|
// Avoid holding db.View and chmu simultaneously to prevent deadlock.
|
|
gridDataByID := make(map[string]GridData)
|
|
a.db.View(func(tx *bbolt.Tx) error {
|
|
grids := tx.Bucket(store.BucketGrids)
|
|
if grids == nil {
|
|
return nil
|
|
}
|
|
for _, craw := range craws {
|
|
grid := grids.Get([]byte(craw.GridID))
|
|
if grid != nil {
|
|
var gd GridData
|
|
if json.Unmarshal(grid, &gd) == nil {
|
|
gridDataByID[craw.GridID] = gd
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
a.chmu.Lock()
|
|
defer a.chmu.Unlock()
|
|
for id, craw := range craws {
|
|
gd, ok := gridDataByID[craw.GridID]
|
|
if !ok {
|
|
continue
|
|
}
|
|
idnum, _ := strconv.Atoi(id)
|
|
c := Character{
|
|
Name: craw.Name,
|
|
ID: idnum,
|
|
Map: gd.Map,
|
|
Position: Position{
|
|
X: craw.Coords.X + (gd.Coord.X * 100),
|
|
Y: craw.Coords.Y + (gd.Coord.Y * 100),
|
|
},
|
|
Type: craw.Type,
|
|
updated: time.Now(),
|
|
}
|
|
old, ok := a.characters[id]
|
|
if !ok {
|
|
a.characters[id] = c
|
|
} else {
|
|
if old.Type == "player" {
|
|
if c.Type == "player" {
|
|
a.characters[id] = c
|
|
} else {
|
|
old.Position = c.Position
|
|
a.characters[id] = old
|
|
}
|
|
} else if old.Type != "unknown" {
|
|
if c.Type != "unknown" {
|
|
a.characters[id] = c
|
|
} else {
|
|
old.Position = c.Position
|
|
a.characters[id] = old
|
|
}
|
|
} else {
|
|
a.characters[id] = c
|
|
}
|
|
}
|
|
}
|
|
}
|