123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package funmow
-
- import (
- "bufio"
- "fmt"
- "github.com/mgutz/ansi"
- "log"
- "net"
- "strings"
- "unicode"
- )
-
- type Client struct {
- conn net.Conn
- connectionID int
- connected bool
- playerID DBRef
- authenticated bool
- inbound chan PlayerEvent
- outbound chan PlayerEvent
- eventDistributor *EventDistributor
- quit chan bool
- db *DB
- factory *ObjectFactory
- }
-
- func NewClient(conn net.Conn, connectionID int, e *EventDistributor, w *DB) *Client {
- c := new(Client)
- c.conn = conn
- c.connectionID = connectionID
- c.connected = true
- c.authenticated = false
- c.inbound = make(chan PlayerEvent)
- c.eventDistributor = e
- c.db = w
- c.factory = NewObjectFactory(w)
-
- return c
- }
-
- func (c *Client) Run() {
-
- log.Print("Received connection from ", c.conn.RemoteAddr())
-
- commandChan := make(chan string)
- dieChan := make(chan bool)
-
- go func() {
- reader := bufio.NewReader(c.conn)
-
- for c.connected {
-
- message, err := reader.ReadString('\n')
- if err != nil {
- dieChan <- true
- break
- }
- message = strings.TrimSpace(message)
- if len(message) > 0 {
- commandChan <- message
- }
- }
- }()
-
- c.splash()
-
- for c.connected {
- select {
- case m := <-c.inbound:
- c.handleInboundEvent(m)
- case cmd := <-commandChan:
- if c.authenticated {
- c.sendCommand(cmd)
- } else {
- c.handleLoginPhase(cmd)
- }
- case <-dieChan:
- c.connected = false
- }
- }
-
- c.conn.Close()
- c.outbound <- PlayerEvent{src: c.playerID, dst: c.playerID, messageType: EventTypeTeardown, connectionID: c.connectionID}
-
- log.Print("Lost connection from ", c.conn.RemoteAddr())
-
- }
-
- func (c *Client) splash() {
-
- c.write(ansi.Color("Welcome to...", "red+b") + "\n")
- c.write(" ___ __ __ ___ __ __\n")
- c.write(" | __| _ _ _ _ | \\/ | / _ \\ \\ \\ / /\n")
- c.write(" | _| | || | | ' \\ | |\\/| | | (_) | \\ \\/\\/ /\n")
- c.write(" |_| \\_,_| |_||_| |_| |_| \\___/ \\_/\\_/\n\n")
- c.write("Commands:\n")
- c.write("To create a player: " + ansi.Color("create <username> <password>", "blue+b") + "\n")
- c.write("To connect: " + ansi.Color("connect <username> <password>", "blue+b") + "\n")
-
- }
-
- func (c *Client) handleLoginPhase(message string) {
-
- fields := strings.FieldsFunc(message, func(c rune) bool {
- return unicode.IsSpace(c)
- })
- switch fields[0] {
- case "help":
- c.write("Commands:\n\tcon[nect] <username>\n\tquit\n")
- case "con":
- fallthrough
- case "connect":
- if len(fields) == 3 {
- player, found := c.db.GetPlayer(fields[1])
- if !found || (found && player.Password != fields[2]) {
- c.write("Bad username or password.\n")
- break
- }
-
- c.playerID = player.ID
- c.authenticated = true
-
- // when a player authenticates, the ipc channels get turned on
- subReq := EventSubscribeRequest{
- connectionID: c.connectionID,
- playerID: c.playerID,
- inbound: c.inbound,
- outbound: make(chan chan PlayerEvent),
- }
-
- c.outbound = c.eventDistributor.Subscribe(subReq)
- c.sendCommand("look")
- } else {
- c.write("What?\n")
- }
- case "create":
- if len(fields) == 3 {
- _, found := c.db.GetPlayer(fields[1])
- if found {
- c.write("That name is already taken.\n")
- break
- }
-
- playerID, _ := c.db.CreatePlayer(strings.TrimSpace(fields[1]), strings.TrimSpace(fields[2]), nil)
-
- _, found = c.db.Fetch(playerID)
- if !found {
- c.write("I can't even.\n")
- break
- }
-
- c.write("You have been created. Now you can connect!\n")
-
- } else {
- c.write("What?\n")
- }
- case "quit":
- c.connected = false
- default:
- c.write("What?\n")
- }
-
- }
-
- func (c *Client) handleInboundEvent(m PlayerEvent) {
- switch m.messageType {
- case EventTypeOutput:
- c.write("%s\n", m.message)
- case EventTypeQuit:
- c.connected = false
- }
- }
-
- func (c *Client) write(format string, a ...interface{}) {
- fmt.Fprintf(c.conn, format, a...)
- }
-
- func (c *Client) sendCommand(message string) {
- c.outbound <- PlayerEvent{src: c.playerID, dst: c.playerID, message: message, messageType: EventTypeCommand, connectionID: c.connectionID}
- }
|