messy WIP; default objects + witch stuff
This commit is contained in:
		
							parent
							
								
									89e4c4b095
								
							
						
					
					
						commit
						1664d678cb
					
				@ -84,6 +84,10 @@ func newServer() (*gameWorldServer, error) {
 | 
			
		||||
		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 {
 | 
			
		||||
		return nil, fmt.Errorf("could not clear sessions: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
@ -91,12 +95,17 @@ func newServer() (*gameWorldServer, error) {
 | 
			
		||||
	s := &gameWorldServer{
 | 
			
		||||
		msgRouter: make(map[string]func(*proto.ClientMessage) error),
 | 
			
		||||
		db:        db,
 | 
			
		||||
		Gateway:   witch.NewGateway(),
 | 
			
		||||
	}
 | 
			
		||||
	gw := witch.NewGateway(s.HandleCmd)
 | 
			
		||||
	s.Gateway = gw
 | 
			
		||||
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *gameWorldServer) HandleCmd(verb, rest string, sender *db.Object) {
 | 
			
		||||
	// TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error {
 | 
			
		||||
	var sid string
 | 
			
		||||
	for {
 | 
			
		||||
@ -129,6 +138,10 @@ func (s *gameWorldServer) Commands(stream proto.GameWorld_CommandsServer) error
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("found avatar %#v", avatar)
 | 
			
		||||
 | 
			
		||||
		s.HandleCmd(cmd.Verb, cmd.Rest, avatar)
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
 | 
			
		||||
			switch cmd.Verb {
 | 
			
		||||
			case "say":
 | 
			
		||||
				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{
 | 
			
		||||
@ -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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		bedroom, err := s.db.BedroomBySessionID(sessionID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			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 {
 | 
			
		||||
			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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										118
									
								
								server/db/db.go
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								server/db/db.go
									
									
									
									
									
								
							@ -26,6 +26,12 @@ type DB interface {
 | 
			
		||||
	EndSession(string) error
 | 
			
		||||
	ClearSessions() error
 | 
			
		||||
 | 
			
		||||
	// General
 | 
			
		||||
	GetObject(owner, name string) (*Object, error)
 | 
			
		||||
 | 
			
		||||
	// Defaults
 | 
			
		||||
	Ensure() error
 | 
			
		||||
 | 
			
		||||
	// Presence
 | 
			
		||||
	ActiveSessions() ([]Session, error)
 | 
			
		||||
	AvatarBySessionID(string) (*Object, error)
 | 
			
		||||
@ -38,6 +44,7 @@ type Account struct {
 | 
			
		||||
	ID     int
 | 
			
		||||
	Name   string
 | 
			
		||||
	Pwhash string
 | 
			
		||||
	God    bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Session struct {
 | 
			
		||||
@ -70,7 +77,59 @@ func NewDB(connURL string) (DB, error) {
 | 
			
		||||
	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) {
 | 
			
		||||
	account = &Account{
 | 
			
		||||
		Name:   name,
 | 
			
		||||
		Pwhash: password,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return account, db.createAccount(account)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (db *pgDB) createAccount(account *Account) (err error) {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	tx, err := db.pool.Begin(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -79,13 +138,8 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
 | 
			
		||||
 | 
			
		||||
	defer tx.Rollback(ctx)
 | 
			
		||||
 | 
			
		||||
	account = &Account{
 | 
			
		||||
		Name:   name,
 | 
			
		||||
		Pwhash: password,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stmt := "INSERT INTO accounts (name, pwhash) VALUES ( $1, $2 ) RETURNING id"
 | 
			
		||||
	err = tx.QueryRow(ctx, stmt, name, password).Scan(&account.ID)
 | 
			
		||||
	stmt := "INSERT INTO accounts (name, pwhash, god) VALUES ( $1, $2, $3 ) RETURNING id"
 | 
			
		||||
	err = tx.QueryRow(ctx, stmt, account.Name, account.Pwhash, account.God).Scan(&account.ID)
 | 
			
		||||
	// TODO handle and cleanup unqiue violations
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
@ -97,10 +151,11 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
 | 
			
		||||
	av := &Object{
 | 
			
		||||
		Avatar: true,
 | 
			
		||||
		Data:   data,
 | 
			
		||||
		Script: "",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stmt = "INSERT INTO objects ( avatar, data, owner ) VALUES ( $1, $2, $3 ) RETURNING id"
 | 
			
		||||
	err = tx.QueryRow(ctx, stmt, av.Avatar, av.Data, account.ID).Scan(&av.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, av.Script).Scan(&av.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@ -117,10 +172,11 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
 | 
			
		||||
	bedroom := &Object{
 | 
			
		||||
		Bedroom: true,
 | 
			
		||||
		Data:    data,
 | 
			
		||||
		Script:  "",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stmt = "INSERT INTO objects ( bedroom, data, owner ) VALUES ( $1, $2, $3 ) RETURNING id"
 | 
			
		||||
	err = tx.QueryRow(ctx, stmt, bedroom.Bedroom, bedroom.Data, account.ID).Scan(&bedroom.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, bedroom.Script).Scan(&bedroom.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@ -131,9 +187,7 @@ func (db *pgDB) CreateAccount(name, password string) (account *Account, err erro
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = tx.Commit(ctx)
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
	return tx.Commit(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if a.Pwhash == "" {
 | 
			
		||||
		return nil, errors.New("this account cannot be logged into")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO hashing lol
 | 
			
		||||
 | 
			
		||||
	if a.Pwhash != password {
 | 
			
		||||
@ -276,6 +334,20 @@ func (db *pgDB) Earshot(obj Object) ([]Object, error) {
 | 
			
		||||
	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) {
 | 
			
		||||
	stmt := `SELECT id, account FROM sessions`
 | 
			
		||||
	rows, err := db.pool.Query(context.Background(), stmt)
 | 
			
		||||
@ -299,6 +371,24 @@ func (db *pgDB) ClearSessions() (err error) {
 | 
			
		||||
	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 {
 | 
			
		||||
	// TODO seeding
 | 
			
		||||
	smells := []string{
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ func newScriptContext(obj db.Object) (*scriptContext, error) {
 | 
			
		||||
	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
 | 
			
		||||
	return nil
 | 
			
		||||
@ -82,12 +82,15 @@ type Gateway struct {
 | 
			
		||||
	// maps game object IDs to script contexts
 | 
			
		||||
	m  map[int]*scriptContext
 | 
			
		||||
	mu sync.RWMutex
 | 
			
		||||
	cb func(string, string, *db.Object)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewGateway() *Gateway {
 | 
			
		||||
func NewGateway(cb func(string, string, *db.Object)) *Gateway {
 | 
			
		||||
	return &Gateway{
 | 
			
		||||
		m:  map[int]*scriptContext{},
 | 
			
		||||
		mu: sync.RWMutex{},
 | 
			
		||||
		// TODO use cb from scriptContext
 | 
			
		||||
		cb: cb,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user