messy WIP; default objects + witch stuff
parent
89e4c4b095
commit
1664d678cb
|
@ -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)
|
||||||
|
|
||||||
|
|
118
server/db/db.go
118
server/db/db.go
|
@ -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{
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue