Implement help command

Resolves #18.
This commit is contained in:
Trevor Slocum 2024-07-19 17:32:30 -07:00
parent a880ed8a36
commit 1e079dcccf
6 changed files with 65 additions and 22 deletions

View file

@ -68,14 +68,17 @@ formatted responses are more easily parsed by computers.
- List all matches.
- Aliases: `ls`
- `create <public>/<private [password]> <points> <acey> [name]`
- Create a match. An `acey` value of 0 represents a standard game, while a value of 1 represents an acey-deucey game.
- `create <public>/<private [password]> <points> <variant> [name]`
- Create a match. A `variant` value of 0 represents a standard game, a value of 1 represents an acey-deucey game and a value of 2 represents a tabula game.
- Aliases: `c`
- `join <id>/<username> [password]`
- Join match by match ID or by player.
- Aliases: `j`
- `leave`
- Leave match.
- `double`
- Offer double to opponent.
- Aliases: `d`
@ -123,7 +126,11 @@ must write some data to the server at least once every 40 seconds.
- `disconnect`
- Disconnect from the server.
- `broadcast`
- `motd [message]`
- View (or set) message of the day.
- Specifying a new message of the day is only available to server administrators.
- `broadcast <message>`
- Send a message to all players.
- This command is only available to server administrators.

View file

@ -58,3 +58,32 @@ const (
EventTypeReplay = "replay"
EventTypeHistory = "history"
)
var HelpText = map[string]string{
CommandLogin: "[username] [password] - Log in. A random username is assigned when none is provided.",
CommandRegister: "<email> <username> <password> - Register an account. A valid email address must be provided.",
CommandResetPassword: "<email> - Request a password reset link via email.",
CommandPassword: "<old> <new> - Change account password.",
CommandSet: "<name> <value> - Change account setting. Available settings: highlight, pips and moves.",
CommandReplay: "<id> - Retrieve replay of the specified game.",
CommandHistory: "<username> [page] - Retrieve match history of the specified player.",
CommandHelp: "[command] - Request help for all commands, or optionally a specific command.",
CommandSay: "<message> - Send a chat message. This command can only be used after creating or joining a match.",
CommandList: "- List all matches.",
CommandCreate: "<public>/<private [password]> <points> <variant> [name] - Create a match. A variant value of 0 represents a standard game, a value of 1 represents an acey-deucey game and a value of 2 represents a tabula game.",
CommandJoin: "<id>/<username> [password] - Join match by match ID or by player.",
CommandLeave: "- Leave match.",
CommandDouble: "- Offer double to opponent.",
CommandResign: "- Resign game. Resigning when a double is offered will decline the offer.",
CommandRoll: "- Roll dice.",
CommandMove: "<from-to> [from-to]... - Move checkers.",
CommandReset: "- Reset pending checker movement.",
CommandOk: "[1-6] - Accept double offer or confirm checker movement. The parameter for this command only applies in acey-deucey games.",
CommandRematch: "- Request (or accept) a rematch after a match has been finished.",
CommandBoard: "- Request current match state.",
CommandPong: "<message> - Sent in response to server ping event to prevent the connection from timing out.",
CommandDisconnect: "- Disconnect from the server.",
CommandMOTD: "[message] - View (or set) message of the day. Specifying a new message of the day is only available to server administrators.",
CommandBroadcast: "<message> - Send a message to all players. This command is only available to server administrators.",
CommandShutdown: "<minutes> <reason> - Prevent the creation of new matches and periodically warn players about the server shutting down. This command is only available to server administrators.",
}

View file

@ -24,12 +24,6 @@ type EventWelcome struct {
Games int
}
type EventHelp struct {
Event
Topic string
Message string
}
type EventPing struct {
Event
Message string
@ -169,8 +163,6 @@ func DecodeEvent(message []byte) (interface{}, error) {
switch e.Type {
case EventTypeWelcome:
ev = &EventWelcome{}
case EventTypeHelp:
ev = &EventHelp{}
case EventTypePing:
ev = &EventPing{}
case EventTypeNotice:

View file

@ -95,8 +95,6 @@ func (c *serverClient) sendEvent(e interface{}) {
switch ev := e.(type) {
case *bgammon.EventWelcome:
ev.Type = bgammon.EventTypeWelcome
case *bgammon.EventHelp:
ev.Type = bgammon.EventTypeHelp
case *bgammon.EventPing:
ev.Type = bgammon.EventTypePing
case *bgammon.EventNotice:
@ -149,10 +147,6 @@ func (c *serverClient) sendEvent(e interface{}) {
switch ev := e.(type) {
case *bgammon.EventWelcome:
c.Write([]byte(fmt.Sprintf("welcome %s there are %d clients playing %d matches.", ev.PlayerName, ev.Clients, ev.Games)))
case *bgammon.EventHelp:
c.Write([]byte("helpstart Help text:"))
c.Write([]byte(fmt.Sprintf("help %s", ev.Message)))
c.Write([]byte("helpend End of help text."))
case *bgammon.EventPing:
c.Write([]byte(fmt.Sprintf("ping %s", ev.Message)))
case *bgammon.EventNotice:

View file

@ -15,7 +15,9 @@ import (
"net/http"
"os"
"os/exec"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"sync"
@ -78,6 +80,8 @@ type server struct {
motd string
sortedCommands []string
mailServer string
passwordSalt string
resetSalt string
@ -108,6 +112,13 @@ func NewServer(tz string, dataSource string, mailServer string, passwordSalt str
}
s.loadLocales()
keys := reflect.ValueOf(bgammon.HelpText).MapKeys()
sortKeys := func(i, j int) bool { return keys[i].Interface().(string) < keys[j].Interface().(string) }
sort.Slice(keys, sortKeys)
for _, key := range keys {
s.sortedCommands = append(s.sortedCommands, key.Interface().(string))
}
if tz != "" {
var err error
s.tz, err = time.LoadLocation(tz)

View file

@ -257,11 +257,21 @@ COMMANDS:
switch keyword {
case bgammon.CommandHelp, "h":
// TODO get extended help by specifying a command after help
cmd.client.sendEvent(&bgammon.EventHelp{
Topic: "",
Message: "Test help text",
})
if len(params) > 0 {
command := string(bytes.ToLower(bytes.Join(params, []byte(" "))))
commandHelp := bgammon.HelpText[command]
if commandHelp != "" {
cmd.client.sendNotice("/" + command + " " + commandHelp)
} else {
cmd.client.sendNotice(fmt.Sprintf("Unknown command: %s", command))
}
continue
}
cmd.client.sendNotice("Available commands:")
for _, command := range s.sortedCommands {
cmd.client.sendNotice("/" + command + " " + bgammon.HelpText[command])
}
case bgammon.CommandJSON:
sendUsage := func() {
cmd.client.sendNotice("To enable JSON formatted messages, send 'json on'. To disable JSON formatted messages, send 'json off'.")