first commit
This commit is contained in:
166
internal/db/repository/character.go
Normal file
166
internal/db/repository/character.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"a301_game_server/internal/db"
|
||||
)
|
||||
|
||||
// CharacterData holds persisted character state.
|
||||
type CharacterData struct {
|
||||
ID int64
|
||||
AccountID int64
|
||||
Name string
|
||||
Level int32
|
||||
Exp int64
|
||||
HP int32
|
||||
MaxHP int32
|
||||
MP int32
|
||||
MaxMP int32
|
||||
Str int32
|
||||
Dex int32
|
||||
IntStat int32
|
||||
ZoneID int32
|
||||
PosX float32
|
||||
PosY float32
|
||||
PosZ float32
|
||||
Rotation float32
|
||||
}
|
||||
|
||||
// CharacterRepo handles character persistence.
|
||||
type CharacterRepo struct {
|
||||
pool *db.Pool
|
||||
}
|
||||
|
||||
// NewCharacterRepo creates a new character repository.
|
||||
func NewCharacterRepo(pool *db.Pool) *CharacterRepo {
|
||||
return &CharacterRepo{pool: pool}
|
||||
}
|
||||
|
||||
// Create inserts a new character.
|
||||
func (r *CharacterRepo) Create(ctx context.Context, accountID int64, name string) (*CharacterData, error) {
|
||||
c := &CharacterData{
|
||||
AccountID: accountID,
|
||||
Name: name,
|
||||
Level: 1,
|
||||
HP: 100,
|
||||
MaxHP: 100,
|
||||
MP: 50,
|
||||
MaxMP: 50,
|
||||
Str: 10,
|
||||
Dex: 10,
|
||||
IntStat: 10,
|
||||
ZoneID: 1,
|
||||
}
|
||||
|
||||
err := r.pool.QueryRow(ctx,
|
||||
`INSERT INTO characters (account_id, name, level, hp, max_hp, mp, max_mp, str, dex, int_stat, zone_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id`,
|
||||
c.AccountID, c.Name, c.Level, c.HP, c.MaxHP, c.MP, c.MaxMP, c.Str, c.Dex, c.IntStat, c.ZoneID,
|
||||
).Scan(&c.ID)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create character: %w", err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetByAccountID returns all characters for an account.
|
||||
func (r *CharacterRepo) GetByAccountID(ctx context.Context, accountID int64) ([]*CharacterData, error) {
|
||||
rows, err := r.pool.Query(ctx,
|
||||
`SELECT id, account_id, name, level, exp, hp, max_hp, mp, max_mp, str, dex, int_stat,
|
||||
zone_id, pos_x, pos_y, pos_z, rotation
|
||||
FROM characters WHERE account_id = $1`, accountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query characters: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var chars []*CharacterData
|
||||
for rows.Next() {
|
||||
c := &CharacterData{}
|
||||
if err := rows.Scan(
|
||||
&c.ID, &c.AccountID, &c.Name, &c.Level, &c.Exp,
|
||||
&c.HP, &c.MaxHP, &c.MP, &c.MaxMP,
|
||||
&c.Str, &c.Dex, &c.IntStat,
|
||||
&c.ZoneID, &c.PosX, &c.PosY, &c.PosZ, &c.Rotation,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("scan character: %w", err)
|
||||
}
|
||||
chars = append(chars, c)
|
||||
}
|
||||
return chars, nil
|
||||
}
|
||||
|
||||
// GetByID loads a single character.
|
||||
func (r *CharacterRepo) GetByID(ctx context.Context, id int64) (*CharacterData, error) {
|
||||
c := &CharacterData{}
|
||||
err := r.pool.QueryRow(ctx,
|
||||
`SELECT id, account_id, name, level, exp, hp, max_hp, mp, max_mp, str, dex, int_stat,
|
||||
zone_id, pos_x, pos_y, pos_z, rotation
|
||||
FROM characters WHERE id = $1`, id,
|
||||
).Scan(
|
||||
&c.ID, &c.AccountID, &c.Name, &c.Level, &c.Exp,
|
||||
&c.HP, &c.MaxHP, &c.MP, &c.MaxMP,
|
||||
&c.Str, &c.Dex, &c.IntStat,
|
||||
&c.ZoneID, &c.PosX, &c.PosY, &c.PosZ, &c.Rotation,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get character %d: %w", id, err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Save persists the current character state.
|
||||
func (r *CharacterRepo) Save(ctx context.Context, c *CharacterData) error {
|
||||
_, err := r.pool.Exec(ctx,
|
||||
`UPDATE characters SET
|
||||
level = $2, exp = $3, hp = $4, max_hp = $5, mp = $6, max_mp = $7,
|
||||
str = $8, dex = $9, int_stat = $10,
|
||||
zone_id = $11, pos_x = $12, pos_y = $13, pos_z = $14, rotation = $15,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1`,
|
||||
c.ID, c.Level, c.Exp, c.HP, c.MaxHP, c.MP, c.MaxMP,
|
||||
c.Str, c.Dex, c.IntStat,
|
||||
c.ZoneID, c.PosX, c.PosY, c.PosZ, c.Rotation,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("save character %d: %w", c.ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveBatch saves multiple characters in a single transaction.
|
||||
func (r *CharacterRepo) SaveBatch(ctx context.Context, chars []*CharacterData) error {
|
||||
if len(chars) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, err := r.pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin tx: %w", err)
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
for _, c := range chars {
|
||||
_, err := tx.Exec(ctx,
|
||||
`UPDATE characters SET
|
||||
level = $2, exp = $3, hp = $4, max_hp = $5, mp = $6, max_mp = $7,
|
||||
str = $8, dex = $9, int_stat = $10,
|
||||
zone_id = $11, pos_x = $12, pos_y = $13, pos_z = $14, rotation = $15,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1`,
|
||||
c.ID, c.Level, c.Exp, c.HP, c.MaxHP, c.MP, c.MaxMP,
|
||||
c.Str, c.Dex, c.IntStat,
|
||||
c.ZoneID, c.PosX, c.PosY, c.PosZ, c.Rotation,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("save character %d in batch: %w", c.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user