123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package funmow
-
- import (
- "bufio"
- "fmt"
- "log"
- "net"
- "strings"
- "unicode"
- )
-
- type Client struct {
- conn net.Conn
- connectionID int
- playerID DBRef
- authenticated bool
- connected bool
- reader *bufio.Reader
- commandChan chan string
- inbound chan PlayerEvent
- outbound chan PlayerEvent
- eventDistributor *EventDistributor
- 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.reader = bufio.NewReader(conn)
- c.authenticated = false
- c.connected = true
- c.commandChan = make(chan string)
- 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())
-
- go func() {
- for c.connected {
- message, err := c.reader.ReadString('\n')
- if err != nil {
- c.connected = false
- return
- }
- message = strings.TrimSpace(message)
- if len(message) > 0 {
- c.commandChan <- message
- }
- }
- }()
-
- c.splash()
-
- for c.connected {
- select {
- case m := <-c.inbound:
- c.handleInboundEvent(m)
- case cmd := <-c.commandChan:
- if c.authenticated {
- c.sendCommand(cmd)
- } else {
- c.handleLoginPhase(cmd)
- }
- }
- }
-
- 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("Welcome to...\n")
- c.write(" ___ __ __ ___ __ __\n")
- c.write(" | __| _ _ _ _ | \\/ | / _ \\ \\ \\ / /\n")
- c.write(" | _| | || | | ' \\ | |\\/| | | (_) | \\ \\/\\/ /\n")
- c.write(" |_| \\_,_| |_||_| |_| |_| \\___/ \\_/\\_/\n\n")
- c.write("use connect <username> <password> to login.\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 {
- playerID, err := c.db.GetPlayerID(fields[1])
- if err != nil {
- c.write("Bad username or password.\n")
- break
- }
-
- c.playerID = playerID
- 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 "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}
- }
|