예제 #1
0
파일: client.go 프로젝트: nparry0/net-rpg
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)"
			}
		}
	}
}
예제 #2
0
/* 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
	}
}
예제 #3
0
파일: client.go 프로젝트: nparry0/net-rpg
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)
}