func recvUpdates(conn *network.GameConn, update chan *network.RoomUpdate, activity chan string) { for { resp, msgType, err := network.Recv(conn) if err != nil { log.Fatal(err) } if msgType == network.TypeRoomUpdate { update <- resp.RoomUpdate } else if msgType == network.TypeResp { if resp.Resp.Message != "" { activity <- resp.Resp.Message } else if !resp.Resp.Success { activity <- "Invalid command (type 'help' and hit enter for assistance)" } } } }
/* Each client gets one of these threads to listen to it, send data to it, and handle validation for the life of the client */ func (client ClientConn) clientReceiver() { for { resp := network.GameMsg{Resp: &network.Resp{Success: false}} req, msgType, err := network.Recv(client.GameConn) if err != nil { if client.room != nil { client.room.CmdChanWriteSync <- RoomHandlerCmd{Pc: client.pc, Cmd: "rem"} <-client.room.CmdChanReadSync } log.Print(err) return } switch msgType { // Log in request case network.TypeLoginReq: // A few sanity checks if req.LoginReq.Version < MIN_CLIENT_VERSION { log.Printf("Attempt to log in with old client version %d (min version is %d)\n", req.LoginReq.Version, MIN_CLIENT_VERSION) resp.Resp.Message = "Your client version is too old for this server. Please update to the latest version." break } else if client.user != nil { log.Printf("Multiple login attempts from %s\n", req.LoginReq.Username) resp.Resp.Message = "ERROR: Duplicate login attempt." break } client.user, err = userLogin(req.LoginReq.Username, req.LoginReq.Password) if err != nil { log.Printf("Failed login for user %s\n", req.LoginReq.Username) resp.Resp.Message = "Incorrect username or password. Please try again." break } // Successfully logged in log.Printf("Successful login from %s\n", req.LoginReq.Username) resp.Resp.Message = "Successfully logged in as " + client.user.Username resp.Resp.Data = client.user.Actors resp.Resp.Success = true // Request to assume actor case network.TypeAssumeActorReq: if client.user == nil { log.Printf("Attempted to assume %s without logging in\n", req.AssumeActorReq.Actor) resp.Resp.Message = "You must log in first" break } else if client.pc != nil { //TODO: Allow user to switch players log.Printf("User %s attempted to assume a second actor %s\n", client.user.Username, req.AssumeActorReq.Actor) resp.Resp.Message = "You cannot play two characters at once." break } client.pc, client.roomCoords, err = NewPc(req.AssumeActorReq.Actor, client.user) if err != nil { log.Printf("User %s failed to assume actor %s\n", client.user.Username, req.AssumeActorReq.Actor) resp.Resp.Message = "Unable to use that character" break } // Successfully assumed an actor. Get our room's channels and ask the room to add us. gWorld.RoomFetcherInChan <- RoomFetcherMsg{Direction: NoDirection, RoomCoords: client.roomCoords} fetcherMsg := <-gWorld.RoomFetcherOutChan client.room = fetcherMsg.Room client.room.CmdChanWriteSync <- RoomHandlerCmd{Pc: client.pc, Cmd: "add", UpdateChan: client.SendChanWrite} resp.Resp.Success = <-client.room.CmdChanReadSync if resp.Resp.Success { log.Printf("User %s successfully assumed actor %s\n", client.user.Username, req.AssumeActorReq.Actor) resp.Resp.Message = "Successfully assumed character " + client.pc.Name } else { log.Printf("User %s failed to enter room with %s\n", client.user.Username, req.AssumeActorReq.Actor) resp.Resp.Message = "Failed to enter room" } // Command case network.TypeCmdReq: // Assign actor req.CmdReq.Actor = client.pc.Name // Validate that it is a supported command, no sense in clogging up the room handler if it's not switch req.CmdReq.Cmd { case "say": fallthrough case "attack": resp.Resp.Success = true client.room.CmdChanWriteAsync <- *req case "go": var dir int resp.Resp.Success = true switch req.CmdReq.Arg1 { case "north": dir = North case "south": dir = South case "east": dir = East case "west": dir = West default: resp.Resp.Success = false } if !resp.Resp.Success { break } coords := *client.roomCoords gWorld.RoomFetcherInChan <- RoomFetcherMsg{Direction: dir, RoomCoords: client.roomCoords} fetcherMsg := <-gWorld.RoomFetcherOutChan if fetcherMsg.Room == nil || fetcherMsg.RoomCoords == nil { // Error from room fetcher resp.Resp.Success = false break } if coords.Row == client.roomCoords.Row && coords.Col == client.roomCoords.Col { resp.Resp.Success = false resp.Resp.Message = "You cannot go that way" break } client.room.CmdChanWriteSync <- RoomHandlerCmd{Pc: client.pc, Cmd: "rem", UpdateChan: client.SendChanWrite} resp.Resp.Success = <-client.room.CmdChanReadSync if !resp.Resp.Success { break } fetcherMsg.Room.CmdChanWriteSync <- RoomHandlerCmd{Pc: client.pc, Cmd: "add", UpdateChan: client.SendChanWrite} resp.Resp.Success = <-fetcherMsg.Room.CmdChanReadSync if !resp.Resp.Success { break } client.room = fetcherMsg.Room resp.Resp.Success = true default: // Don't log to server logs every time someone mistypes a command resp.Resp.Message = "Invalid command" } default: log.Printf("Recv'd invalid type: %d\n", msgType) resp.Resp.Message = "ERROR: Invalid message type (" + strconv.Itoa(msgType) + ")." } // Send response and listen for another message client.SendChanWrite <- resp } }
func main() { log.SetFlags(log.Lshortfile) // Prompt the user for their name and pass var name, pass, character string fmt.Printf("*** Stuff N' Things the RPG ***\n") fmt.Printf("Login:"******"Password:"******"Logging in as %s\n", name) req := network.GameMsg{LoginReq: &network.LoginReq{Version: 1, Username: name, Password: pass}} //log.Printf("main: %s\n", req); // Connect to the server conn, err := network.Connect("") if err != nil { log.Fatal(err) } // Send the request err = network.Send(conn, req) if err != nil { log.Fatal(err) } resp, msgType, err := network.Recv(conn) if err != nil { log.Fatal(err) } // Did we log in successfully? if msgType == network.TypeResp && resp.Resp.Success == true { fmt.Printf("Login Successful :)\n") } else { fmt.Printf("Login Failed :(\n") fmt.Printf("Server says: %s\n", resp.Resp.Message) os.Exit(1) } // Character select fmt.Printf("Available characters:\n") for index, each := range resp.Resp.Data { fmt.Printf("%d) %s\n", index+1, each) } fmt.Printf("Which character would you like to play? ") fmt.Scanln(&character) req = network.GameMsg{AssumeActorReq: &network.AssumeActorReq{Actor: character}} // Send the request err = network.Send(conn, req) if err != nil { log.Fatal(err) } update := make(chan *network.RoomUpdate) activity := make(chan string) sendChanWrite, sendChanRead := network.NewPipe() go sendCmds(conn, sendChanRead) go recvUpdates(conn, update, activity) // Set up the UI // TODO: make this whole deal an object, add character and other stuff to it as a member startUI(update, activity, sendChanWrite, character) }