Browse Source

Bit of flags, some permissions, passwords.

Keelan Lightfoot 8 years ago
parent
commit
9e5591fbcf
6 changed files with 215 additions and 44 deletions
  1. 28
    3
      client.go
  2. 2
    2
      cmd/funmow/main.go
  3. 29
    27
      db.go
  4. 6
    0
      event_distributor.go
  5. 116
    9
      execution_context.go
  6. 34
    3
      object.go

+ 28
- 3
client.go View File

104
 		fallthrough
104
 		fallthrough
105
 	case "connect":
105
 	case "connect":
106
 		if len(fields) == 3 {
106
 		if len(fields) == 3 {
107
-			playerID, err := c.db.GetPlayerID(fields[1])
108
-			if err != nil {
107
+			player, found := c.db.GetPlayer(fields[1])
108
+			if !found || (found && player.Password != fields[2]) {
109
 				c.write("Bad username or password.\n")
109
 				c.write("Bad username or password.\n")
110
 				break
110
 				break
111
 			}
111
 			}
112
+			
113
+
114
+			c.playerID = player.ID
115
+			c.authenticated = true
116
+
117
+			// when a player authenticates, the ipc channels get turned on
118
+			subReq := EventSubscribeRequest{
119
+				connectionID: c.connectionID,
120
+				playerID:     c.playerID,
121
+				inbound:      c.inbound,
122
+				outbound:     make(chan chan PlayerEvent),
123
+			}
112
 
124
 
113
-			c.playerID = playerID
125
+			c.outbound = c.eventDistributor.Subscribe(subReq)
126
+			c.sendCommand("look")
127
+		} else {
128
+			c.write("What?\n")
129
+		}
130
+	case "create":
131
+		if len(fields) == 3 {
132
+			player, found := c.db.GetPlayer(fields[1])
133
+			if !found || (found && player.Password != fields[2]) {
134
+				c.write("Bad username or password.\n")
135
+				break
136
+			}
137
+			
138
+			c.playerID = player.ID
114
 			c.authenticated = true
139
 			c.authenticated = true
115
 
140
 
116
 			// when a player authenticates, the ipc channels get turned on
141
 			// when a player authenticates, the ipc channels get turned on

+ 2
- 2
cmd/funmow/main.go View File

50
 
50
 
51
 	f := funmow.NewObjectFactory(db)
51
 	f := funmow.NewObjectFactory(db)
52
 
52
 
53
-	keelan, _ := db.CreatePlayer("keelan")
54
-	dan, _ := db.CreatePlayer("dan")
53
+	keelan, _ := db.CreatePlayer("keelan", map[string]string{"wizard":"true"})
54
+	dan, _ := db.CreatePlayer("dan", nil)
55
 
55
 
56
 	outside := f.NewObject()
56
 	outside := f.NewObject()
57
 	outside.Type = "room"
57
 	outside.Type = "room"

+ 29
- 27
db.go View File

4
 	"bytes"
4
 	"bytes"
5
 	"encoding/binary"
5
 	"encoding/binary"
6
 	"encoding/json"
6
 	"encoding/json"
7
-	"errors"
8
 	"fmt"
7
 	"fmt"
9
 	"github.com/boltdb/bolt"
8
 	"github.com/boltdb/bolt"
10
 	"strconv"
9
 	"strconv"
233
 	})
232
 	})
234
 }
233
 }
235
 
234
 
236
-func (s *DB) SetPlayerID(name string, id DBRef) error {
235
+func (s *DB) SetPlayer(name string, player PlayerMeta) error {
237
 
236
 
238
 	err := s.db.Update(func(tx *bolt.Tx) error {
237
 	err := s.db.Update(func(tx *bolt.Tx) error {
238
+		
239
+		buf, err := json.Marshal(player)
240
+
241
+		if err != nil { return err }
242
+	
239
 		b := tx.Bucket([]byte("player"))
243
 		b := tx.Bucket([]byte("player"))
240
-		if b == nil {
241
-			return errors.New("Player bucket not found")
242
-		}
243
-		return b.Put([]byte(name), id.Key())
244
+		
245
+		return b.Put([]byte(name), buf)
244
 	})
246
 	})
245
 
247
 
246
-	if DEBUG {
247
-		fmt.Printf("SetPlayerID name: %s id: %d\n", name, id)
248
-	}
249
-
250
 	return err
248
 	return err
251
 
249
 
252
 }
250
 }
253
 
251
 
254
-func (s *DB) GetPlayerID(name string) (DBRef, error) {
255
-	var id DBRef
256
-	err := s.db.View(func(tx *bolt.Tx) error {
252
+
253
+
254
+
255
+func (s *DB) GetPlayer(name string) (PlayerMeta, bool) {
256
+	var player PlayerMeta
257
+	found := false
258
+	
259
+	s.db.View(func(tx *bolt.Tx) error {
257
 		b := tx.Bucket([]byte("player"))
260
 		b := tx.Bucket([]byte("player"))
258
-		if b == nil {
259
-			return errors.New("Player bucket not found")
260
-		}
261
 		v := b.Get([]byte(name))
261
 		v := b.Get([]byte(name))
262
-		if v == nil {
263
-			return errors.New("Player not found")
262
+		if v == nil { return nil }
263
+		err := json.Unmarshal(v, &player)
264
+		if err == nil {
265
+			found = true
264
 		}
266
 		}
265
-		id = NewDBRefFromKey(v)
266
 		return nil
267
 		return nil
267
 	})
268
 	})
268
 
269
 
269
-	if DEBUG {
270
-		fmt.Printf("GetPlayerID name: %s id: %d\n", name, id)
271
-	}
272
-
273
-	return id, err
270
+	return player, found
274
 }
271
 }
275
 
272
 
276
-func (s *DB) CreatePlayer(name string) (DBRef, error) {
273
+func (s *DB) CreatePlayer(name string, flags map[string]string) (DBRef, error) {
277
 
274
 
278
 	var playerID DBRef
275
 	var playerID DBRef
279
 
276
 
285
 			return err
282
 			return err
286
 		}
283
 		}
287
 		playerID = DBRef(seq)
284
 		playerID = DBRef(seq)
288
-		s.txStoreObject(objectBucket, Object{ID: playerID, Name: name, Type: "player"}, playerID)
289
-		err = playerBucket.Put([]byte(name), playerID.Key())
285
+		s.txStoreObject(objectBucket, Object{ID: playerID, Name: name, Type: "player", Flags: flags}, playerID)
286
+		playerMeta := PlayerMeta{ID: playerID, Password: "password"}
287
+		buf, err := json.Marshal(playerMeta)
288
+		if err != nil {
289
+			return err
290
+		}
291
+		err = playerBucket.Put([]byte(name), buf)
290
 		return err
292
 		return err
291
 	})
293
 	})
292
 
294
 

+ 6
- 0
event_distributor.go View File

14
 	EventTypeTeardown
14
 	EventTypeTeardown
15
 	EventTypeTeardownComplete
15
 	EventTypeTeardownComplete
16
 	EventTypeForce
16
 	EventTypeForce
17
+	EventTypeLogin
18
+	EventTypeSystem
17
 )
19
 )
18
 
20
 
19
 type PlayerEvent struct {
21
 type PlayerEvent struct {
102
 					execContext: c,
104
 					execContext: c,
103
 					connInbound: make(map[int]chan PlayerEvent),
105
 					connInbound: make(map[int]chan PlayerEvent),
104
 				}
106
 				}
107
+				// mark player as online, and tell everyone!
108
+				e.players[sub.playerID].execInbound <- PlayerEvent{messageType: EventTypeLogin}
105
 			}
109
 			}
106
 			reg := e.players[sub.playerID]
110
 			reg := e.players[sub.playerID]
107
 			reg.connInbound[sub.connectionID] = sub.inbound
111
 			reg.connInbound[sub.connectionID] = sub.inbound
157
 				e.broadcastEvent(event, false)
161
 				e.broadcastEvent(event, false)
158
 			case EventTypeWall:
162
 			case EventTypeWall:
159
 				e.broadcastEvent(event, false)
163
 				e.broadcastEvent(event, false)
164
+			case EventTypeSystem:
165
+				e.broadcastEvent(event, false)
160
 			}
166
 			}
161
 		}
167
 		}
162
 	}
168
 	}

+ 116
- 9
execution_context.go View File

37
 	if !found {
37
 	if !found {
38
 		return nil
38
 		return nil
39
 	}
39
 	}
40
+	
41
+	
40
 
42
 
41
 	c.actor = actor
43
 	c.actor = actor
42
 	c.outbound = outbound
44
 	c.outbound = outbound
100
 			}
102
 			}
101
 			c.HandleEvent(event)
103
 			c.HandleEvent(event)
102
 		}
104
 		}
105
+		// mark player as offline
106
+		if c.actor.Type == "player" {
107
+			c.actor.SetFlag("online", "false")
108
+			c.actor.Commit()
109
+		}
103
 		// and finally we tell the event distributor to delete us.
110
 		// and finally we tell the event distributor to delete us.
104
 		c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeTeardownComplete}
111
 		c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeTeardownComplete}
105
 	}()
112
 	}()
110
 func (c *ExecutionContext) HandleEvent(m PlayerEvent) {
117
 func (c *ExecutionContext) HandleEvent(m PlayerEvent) {
111
 	inside, _ := c.db.GetParent(c.actor.ID)
118
 	inside, _ := c.db.GetParent(c.actor.ID)
112
 	switch m.messageType {
119
 	switch m.messageType {
120
+	case EventTypeLogin:
121
+		if c.actor.Type == "player" {
122
+			c.actor.SetFlag("online", "true")
123
+			c.actor.Commit()
124
+			inside, _ := c.db.GetParent(c.actor.ID)
125
+			c.system("Yay! %s has connected! Oh boy!", c.actor.Name)
126
+			c.oemit(inside, "You hear a rustling as %s awakens from a slumber.", c.actor.Name)
127
+		}
113
 	case EventTypeEmit:
128
 	case EventTypeEmit:
114
 		fallthrough
129
 		fallthrough
115
 	case EventTypeOEmit:
130
 	case EventTypeOEmit:
123
 		if !found {
138
 		if !found {
124
 			break
139
 			break
125
 		}
140
 		}
126
-		c.output("In the distance, you hear %s bellow out \"%s\"", speaker.Name, m.message)
141
+		c.output("In the distance, you hear %s bellow out: \"%s\"", speaker.Name, m.message)
142
+	case EventTypeSystem:
143
+		c.output(m.message)
127
 	case EventTypePage:
144
 	case EventTypePage:
128
 		speaker, found := c.db.Fetch(m.src)
145
 		speaker, found := c.db.Fetch(m.src)
129
 		if !found {
146
 		if !found {
222
 		c.destroyCmd(strings.TrimPrefix(message, "@destroy "))
239
 		c.destroyCmd(strings.TrimPrefix(message, "@destroy "))
223
 	case strings.HasPrefix(message, "@force "):
240
 	case strings.HasPrefix(message, "@force "):
224
 		c.forceCmd(message)
241
 		c.forceCmd(message)
242
+	case strings.HasPrefix(message, "@wizard "):
243
+		c.playerFlagCmd(message, "wizard")
244
+		
225
 	default:
245
 	default:
226
 		if !c.goCmd(message) {
246
 		if !c.goCmd(message) {
227
 			c.output("What?\n")
247
 			c.output("What?\n")
335
 	}
355
 	}
336
 
356
 
337
 	objectID, err := NewDBRefFromHashRef(objectName)
357
 	objectID, err := NewDBRefFromHashRef(objectName)
338
-	wizard := false
358
+	wizard := c.actor.GetFlag("wizard","false") == "true"
339
 	if err == nil {
359
 	if err == nil {
340
 		object, found := c.db.Fetch(objectID)
360
 		object, found := c.db.Fetch(objectID)
341
 		if !found {
361
 		if !found {
342
 			c.output("I can't force what doesn't exist.")
362
 			c.output("I can't force what doesn't exist.")
343
 		}
363
 		}
344
-		if object.Type == "thing" || (object.Type == "player" && wizard) {
345
-			c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
346
-		} else {
364
+		if object.Type != "thing" && object.Type != "player" {
347
 			c.output("Some things just can't be forced.")
365
 			c.output("Some things just can't be forced.")
366
+			return
348
 		}
367
 		}
368
+		if object.Type == "player" && !wizard {
369
+			c.output("It's not nice to force others to do your bidding.")
370
+			return
371
+		} 
372
+		if object.Owner != c.actor.ID && !wizard {
373
+			c.output("It's not nice to touch other people's things.")
374
+			return
375
+		} 
376
+		c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
377
+
349
 	} else {
378
 	} else {
350
 
379
 
351
 		object, matchType := room.MatchLinkNames(objectName, c.actor.ID).ExactlyOne()
380
 		object, matchType := room.MatchLinkNames(objectName, c.actor.ID).ExactlyOne()
352
 
381
 
353
 		switch matchType {
382
 		switch matchType {
354
 		case MatchOne:
383
 		case MatchOne:
355
-			if object.Type == "thing" || (object.Type == "player" && wizard) {
356
-				c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
357
-			} else {
384
+			if object.Type != "thing" && object.Type != "player" {
358
 				c.output("Some things just can't be forced.")
385
 				c.output("Some things just can't be forced.")
386
+				return
359
 			}
387
 			}
388
+			if object.Type == "player" && !wizard {
389
+				c.output("It's not nice to force others to do your bidding.")
390
+				return
391
+			} 
392
+			if object.Owner != c.actor.ID && !wizard {
393
+				c.output("It's not nice to touch other people's things.")
394
+				return
395
+			} 
396
+			c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
360
 		case MatchNone:
397
 		case MatchNone:
361
 			c.output("I don't see that here.")
398
 			c.output("I don't see that here.")
362
 		case MatchMany:
399
 		case MatchMany:
408
 			c.output("You can't pick yourself up.")
445
 			c.output("You can't pick yourself up.")
409
 			return
446
 			return
410
 		}
447
 		}
448
+		if object.Type == "room" {
449
+			c.output("You can't carry a whole room, silly!")
450
+			return
451
+		}
411
 		err := c.actor.Contains(&object)
452
 		err := c.actor.Contains(&object)
412
 		if err != nil {
453
 		if err != nil {
413
 			return
454
 			return
464
 
505
 
465
 	switch matchType {
506
 	switch matchType {
466
 	case MatchOne:
507
 	case MatchOne:
508
+		if object.Type == "player" {
509
+			c.output("Maybe you should seek consent prior to entering another player.")
510
+			return
511
+		}
512
+		if object.Type == "exit" {
513
+			c.output("This s not how exits are meant to be used.")
514
+			return
515
+		}
467
 		if object.ID == c.actor.ID {
516
 		if object.ID == c.actor.ID {
468
 			c.output("Entering yourself would be a bad idea.")
517
 			c.output("Entering yourself would be a bad idea.")
469
 			return
518
 			return
677
 		candidate.Name = name
726
 		candidate.Name = name
678
 		candidate.Commit()
727
 		candidate.Commit()
679
 		c.output("Name set.")
728
 		c.output("Name set.")
680
-		//c.actor.Refresh()
681
 	case MatchNone:
729
 	case MatchNone:
682
 		c.output("I don't see that here.")
730
 		c.output("I don't see that here.")
683
 	case MatchMany:
731
 	case MatchMany:
686
 
734
 
687
 }
735
 }
688
 
736
 
737
+
738
+
739
+func (c *ExecutionContext) playerFlagCmd(input string, flag string) {
740
+	r, _ := regexp.Compile(`^@`+flag+`\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
741
+	params := r.FindStringSubmatch(input)
742
+	if params == nil {
743
+		return
744
+	}
745
+
746
+	playerName, value := params[1], params[2]
747
+
748
+	playerMeta,found := c.db.GetPlayer(playerName)
749
+	
750
+	
751
+	if found {
752
+	
753
+		player, found := c.db.Fetch(playerMeta.ID)
754
+
755
+		if !found {
756
+			return
757
+		}
758
+		
759
+		player.SetFlag(flag, value)
760
+		player.Commit()
761
+		c.output("It is so.")
762
+	} else {
763
+		c.output("I don't know who that is.")
764
+	}
765
+}
766
+
689
 func (c *ExecutionContext) descCmd(input string) {
767
 func (c *ExecutionContext) descCmd(input string) {
690
 
768
 
691
 	r, _ := regexp.Compile(`^@desc\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
769
 	r, _ := regexp.Compile(`^@desc\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
744
 		c.output("That doesn't exist.")
822
 		c.output("That doesn't exist.")
745
 		return
823
 		return
746
 	}
824
 	}
825
+	
826
+	if newRoom.Type == "exit" {
827
+		c.output("As fun is it sounds, you're not going to teleport into an exit.")
828
+		return
829
+	}
830
+	
831
+	if newRoom.Type == "player" {
832
+		c.output("Teleporting into other players is very impolite.")
833
+		return
834
+	}
835
+	
836
+	if newRoom.ID == c.actor.ID {
837
+		c.output("Teleporting to yourself is generally considered dangerous.")
838
+		return
839
+	}
747
 
840
 
748
 	c.output("You feel an intense wooshing sensation.")
841
 	c.output("You feel an intense wooshing sensation.")
749
 	err = newRoom.Contains(&c.actor)
842
 	err = newRoom.Contains(&c.actor)
847
 
940
 
848
 }
941
 }
849
 
942
 
943
+func (c *ExecutionContext) wall(format string, a ...interface{}) {
944
+
945
+	message := fmt.Sprintf(format, a...)
946
+	c.outbound <- PlayerEvent{src: c.actor.ID, message: message, messageType: EventTypeWall}
947
+
948
+}
949
+
950
+func (c *ExecutionContext) system(format string, a ...interface{}) {
951
+
952
+	message := fmt.Sprintf(format, a...)
953
+	c.outbound <- PlayerEvent{src: c.actor.ID, message: message, messageType: EventTypeSystem}
954
+
955
+}
956
+
850
 func (c *ExecutionContext) oemit(audience DBRef, format string, a ...interface{}) {
957
 func (c *ExecutionContext) oemit(audience DBRef, format string, a ...interface{}) {
851
 
958
 
852
 	message := fmt.Sprintf(format, a...)
959
 	message := fmt.Sprintf(format, a...)

+ 34
- 3
object.go View File

12
 	MatchMany
12
 	MatchMany
13
 )
13
 )
14
 
14
 
15
+type PlayerMeta struct {
16
+	ID          DBRef  `json:"id"`
17
+	Password    string `json:"password"`
18
+}
19
+
15
 type Object struct {
20
 type Object struct {
16
 	ID          DBRef  `json:"id"`
21
 	ID          DBRef  `json:"id"`
17
 	Next        DBRef  `json:"next"`
22
 	Next        DBRef  `json:"next"`
18
 	Type        string `json:"type"`
23
 	Type        string `json:"type"`
19
 	Name        string `json:"name"`
24
 	Name        string `json:"name"`
20
 	Description string `json:"description"`
25
 	Description string `json:"description"`
21
-	//Links       map[string]map[string]bool `json:"links"`
22
-	//Inside      DBRef                      `json:"inside"`
26
+	Flags		map[string]string `json:"flags"`
23
 	Owner DBRef `json:"owner"`
27
 	Owner DBRef `json:"owner"`
24
 	db    *DB
28
 	db    *DB
25
 }
29
 }
184
 		}
188
 		}
185
 		o, found := o.db.Fetch(childID)
189
 		o, found := o.db.Fetch(childID)
186
 		if found {
190
 		if found {
187
-			if linkType == "exit" {
191
+			if linkType == "player" {
192
+				if o.GetFlag("online","false") == "true" {
193
+					r = append(r, o.DetailedName())
194
+				}
195
+			} else if linkType == "exit" {
188
 				r = append(r, o.Name)
196
 				r = append(r, o.Name)
189
 			} else {
197
 			} else {
190
 				r = append(r, o.DetailedName())
198
 				r = append(r, o.DetailedName())
196
 	return r
204
 	return r
197
 }
205
 }
198
 
206
 
207
+func (o *Object) SetFlag(flag string, value string) {
208
+	if o.Flags == nil {
209
+		o.Flags = make(map[string]string)
210
+	}
211
+	o.Flags[flag]=value
212
+}
213
+
214
+func (o *Object) GetFlag(flag string, defaultValue string) (string) {
215
+	
216
+	if o.Flags == nil {
217
+		return defaultValue
218
+	}
219
+	
220
+	value, ok := o.Flags[flag]
221
+	
222
+	if !ok {
223
+		return defaultValue
224
+	}
225
+	
226
+	return value
227
+}
228
+
229
+
199
 type ObjectList []Object
230
 type ObjectList []Object
200
 
231
 
201
 func (l ObjectList) First() Object {
232
 func (l ObjectList) First() Object {