messy WIP; default objects + witch stuff

trunk
vilmibm 2022-12-22 22:03:37 -08:00
parent 89e4c4b095
commit 1664d678cb
4 changed files with 156 additions and 37 deletions

View File

@ -84,6 +84,10 @@ func newServer() (*gameWorldServer, error) {
return nil, err return nil, err
} }
if err = db.Ensure(); err != nil {
return nil, fmt.Errorf("failed to ensure default entities: %w", err)
}
if err = db.ClearSessions(); err != nil { if err = db.ClearSessions(); err != nil {
return nil, fmt.Errorf("could not clear sessions: %w", err) return nil, fmt.Errorf("could not clear sessions: %w", err)
} }
@ -91,12 +95,17 @@ func newServer() (*gameWorldServer, error) {
s := &gameWorldServer{ s := &gameWorldServer{
msgRouter: make(map[string]func(*proto.ClientMessage) error), msgRouter: make(map[string]func(*proto.ClientMessage) error),
db: db, db: db,
Gateway: witch.NewGateway(),
} }
gw := witch.NewGateway(s.HandleCmd)
s.Gateway = gw
return s, nil return s, nil
} }
func (s *gameWorldServer) HandleCmd(verb, rest string, sender *db.Object) {
// TODO
}
func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error { func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error {
var sid string var sid string
for { for {
@ -129,6 +138,10 @@ func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error
} }
log.Printf("found avatar %#v", avatar) log.Printf("found avatar %#v", avatar)
s.HandleCmd(cmd.Verb, cmd.Rest, avatar)
/*
switch cmd.Verb { switch cmd.Verb {
case "say": case "say":
if err = s.HandleSay(avatar, cmd.Rest); err != nil { if err = s.HandleSay(avatar, cmd.Rest); err != nil {
@ -144,6 +157,8 @@ func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error
} }
} }
*/
/* /*
msg := &proto.ClientMessage{ msg := &proto.ClientMessage{
@ -202,6 +217,7 @@ func (s *gameWorldServer) Register(ctx context.Context, auth *proto.AuthInfo) (s
return nil, fmt.Errorf("failed to find avatar for %s: %w", sessionID, err) return nil, fmt.Errorf("failed to find avatar for %s: %w", sessionID, err)
} }
/*
bedroom, err := s.db.BedroomBySessionID(sessionID) bedroom, err := s.db.BedroomBySessionID(sessionID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to find bedroom for %s: %w", sessionID, err) return nil, fmt.Errorf("failed to find bedroom for %s: %w", sessionID, err)
@ -211,6 +227,16 @@ func (s *gameWorldServer) Register(ctx context.Context, auth *proto.AuthInfo) (s
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to move %d into %d: %w", av.ID, bedroom.ID, err) return nil, fmt.Errorf("failed to move %d into %d: %w", av.ID, bedroom.ID, err)
} }
*/
foyer, err := s.db.GetObject("system", "foyer")
if err != nil {
return nil, fmt.Errorf("failed to find foyer: %w", err)
}
if err = s.db.MoveInto(*av, *foyer); err != nil {
return nil, fmt.Errorf("failed to move %d into %d: %w", av.ID, foyer.ID, err)
}
// TODO send room info, avatar info to client (need to figure this out and update proto) // TODO send room info, avatar info to client (need to figure this out and update proto)

View File

@ -26,6 +26,12 @@ type DB interface {
EndSession(string) error EndSession(string) error
ClearSessions() error ClearSessions() error
// General
GetObject(owner, name string) (*Object, error)
// Defaults
Ensure() error
// Presence // Presence
ActiveSessions() ([]Session, error) ActiveSessions() ([]Session, error)
AvatarBySessionID(string) (*Object, error) AvatarBySessionID(string) (*Object, error)
@ -38,6 +44,7 @@ type Account struct {
ID int ID int
Name string Name string
Pwhash string Pwhash string
God bool
} }
type Session struct { type Session struct {
@ -70,7 +77,59 @@ func NewDB(connURL string) (DB, error) {
return pgdb, nil return pgdb, nil
} }
// Ensure checks for and then creates default resources if they do not exist (like the Foyer)
func (db *pgDB) Ensure() error {
// TODO this is sloppy but shrug
_, err := db.pool.Exec(context.Background(), schema)
//log.Println(err)
sysAcc, err := db.GetAccount("system")
if err != nil {
// TODO actually check error. for now assuming it means does not exist
sysAcc, err = db.CreateGod("system", "")
if err != nil {
return fmt.Errorf("failed to create system account: %w", err)
}
}
log.Printf("%#v", sysAcc)
if _, err := db.GetObject("system", "foyer"); err != nil {
data := map[string]string{}
data["name"] = "foyer"
data["description"] = "a big room. the ceiling is painted with constellations."
foyer := &Object{
Data: data,
Script: "",
// TODO default room script
}
if err = db.CreateObject(sysAcc, foyer); err != nil {
return err
}
}
return nil
}
func (db *pgDB) CreateGod(name, password string) (account *Account, err error) {
account = &Account{
Name: name,
Pwhash: password,
God: true,
}
return account, db.createAccount(account)
}
func (db *pgDB) CreateAccount(name, password string) (account *Account, err error) { func (db *pgDB) CreateAccount(name, password string) (account *Account, err error) {
account = &Account{
Name: name,
Pwhash: password,
}
return account, db.createAccount(account)
}
func (db *pgDB) createAccount(account *Account) (err error) {
ctx := context.Background() ctx := context.Background()
tx, err := db.pool.Begin(ctx) tx, err := db.pool.Begin(ctx)
if err != nil { if err != nil {
@ -79,13 +138,8 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
defer tx.Rollback(ctx) defer tx.Rollback(ctx)
account = &Account{ stmt := "INSERT INTO accounts (name, pwhash, god) VALUES ( $1, $2, $3 ) RETURNING id"
Name: name, err = tx.QueryRow(ctx, stmt, account.Name, account.Pwhash, account.God).Scan(&account.ID)
Pwhash: password,
}
stmt := "INSERT INTO accounts (name, pwhash) VALUES ( $1, $2 ) RETURNING id"
err = tx.QueryRow(ctx, stmt, name, password).Scan(&account.ID)
// TODO handle and cleanup unqiue violations // TODO handle and cleanup unqiue violations
if err != nil { if err != nil {
return return
@ -97,10 +151,11 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
av := &Object{ av := &Object{
Avatar: true, Avatar: true,
Data: data, Data: data,
Script: "",
} }
stmt = "INSERT INTO objects ( avatar, data, owner ) VALUES ( $1, $2, $3 ) RETURNING id" stmt = "INSERT INTO objects ( avatar, data, owner, script ) VALUES ( $1, $2, $3, $4 ) RETURNING id"
err = tx.QueryRow(ctx, stmt, av.Avatar, av.Data, account.ID).Scan(&av.ID) err = tx.QueryRow(ctx, stmt, av.Avatar, av.Data, account.ID, av.Script).Scan(&av.ID)
if err != nil { if err != nil {
return return
} }
@ -117,10 +172,11 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
bedroom := &Object{ bedroom := &Object{
Bedroom: true, Bedroom: true,
Data: data, Data: data,
Script: "",
} }
stmt = "INSERT INTO objects ( bedroom, data, owner ) VALUES ( $1, $2, $3 ) RETURNING id" stmt = "INSERT INTO objects ( bedroom, data, owner, script ) VALUES ( $1, $2, $3, $4 ) RETURNING id"
err = tx.QueryRow(ctx, stmt, bedroom.Bedroom, bedroom.Data, account.ID).Scan(&bedroom.ID) err = tx.QueryRow(ctx, stmt, bedroom.Bedroom, bedroom.Data, account.ID, bedroom.Script).Scan(&bedroom.ID)
if err != nil { if err != nil {
return return
} }
@ -131,9 +187,7 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
return return
} }
err = tx.Commit(ctx) return tx.Commit(ctx)
return
} }
func (db *pgDB) ValidateCredentials(name, password string) (*Account, error) { func (db *pgDB) ValidateCredentials(name, password string) (*Account, error) {
@ -142,6 +196,10 @@ func (db *pgDB) ValidateCredentials(name, password string) (*Account, error) {
return nil, err return nil, err
} }
if a.Pwhash == "" {
return nil, errors.New("this account cannot be logged into")
}
// TODO hashing lol // TODO hashing lol
if a.Pwhash != password { if a.Pwhash != password {
@ -276,6 +334,20 @@ func (db *pgDB) Earshot(obj Object) ([]Object, error) {
return out, nil return out, nil
} }
func (db *pgDB) GetObject(owner, name string) (obj *Object, err error) {
ctx := context.Background()
obj = &Object{}
stmt := `
SELECT id, avatar, data, owner, script
FROM objects
WHERE owner = $1 AND data['name'] = $2`
err = db.pool.QueryRow(ctx, stmt, owner, fmt.Sprintf(`"%s"`, name)).Scan(
&obj.ID, &obj.Avatar, &obj.Data, &obj.OwnerID, &obj.Script)
// TODO i think the escaping here is going to create a sadness ^
return
}
func (db *pgDB) ActiveSessions() (out []Session, err error) { func (db *pgDB) ActiveSessions() (out []Session, err error) {
stmt := `SELECT id, account FROM sessions` stmt := `SELECT id, account FROM sessions`
rows, err := db.pool.Query(context.Background(), stmt) rows, err := db.pool.Query(context.Background(), stmt)
@ -299,6 +371,24 @@ func (db *pgDB) ClearSessions() (err error) {
return return
} }
func (db *pgDB) CreateObject(owner *Account, obj *Object) error {
ctx := context.Background()
stmt := `
INSERT INTO objects (avatar, bedroom, data, script, owner)
VALUES ( $1, $2, $3, $4, $5)
RETURNING id
`
err := db.pool.QueryRow(ctx, stmt,
obj.Avatar, obj.Bedroom, obj.Data, obj.Script, owner.ID).Scan(
&obj.ID)
if err != nil {
return err
}
return nil
}
func randSmell() string { func randSmell() string {
// TODO seeding // TODO seeding
smells := []string{ smells := []string{

View File

@ -72,7 +72,7 @@ func newScriptContext(obj db.Object) (*scriptContext, error) {
return &scriptContext{}, nil return &scriptContext{}, nil
} }
func (sc *scriptContext) Handle(ver, rest string, sender, target *db.Object) error { func (sc *scriptContext) Handle(verb, rest string, sender, target *db.Object) error {
// TODO call _handle function from the Lstate // TODO call _handle function from the Lstate
return nil return nil
@ -82,12 +82,15 @@ type Gateway struct {
// maps game object IDs to script contexts // maps game object IDs to script contexts
m map[int]*scriptContext m map[int]*scriptContext
mu sync.RWMutex mu sync.RWMutex
cb func(string, string, *db.Object)
} }
func NewGateway() *Gateway { func NewGateway(cb func(string, string, *db.Object)) *Gateway {
return &Gateway{ return &Gateway{
m: map[int]*scriptContext{}, m: map[int]*scriptContext{},
mu: sync.RWMutex{}, mu: sync.RWMutex{},
// TODO use cb from scriptContext
cb: cb,
} }
} }