So today has actually been a productive day, which is… not always a thing for me, let's just say that. Especially lately.
Anyway, today I finalised the first real command for my own Twitch chat bot, YomiOnoBot: !yomi-info. It's not a complicated command or anything, but the work put into it underpins a lot of the stuff I want the bot to do Eventually™, so it's not all bad.
At a basic level, the !yomi-info command enables chatters (and strimmer!) to look up stuff about the Nioh 2 Underworld:
< chatter> !yomi-help
< YomiOnoBot> For info on a floor of the Underworld, say !yomi-info <floor number>, e.g. !yomi-info 5
< chatter> !yomi-info 5
< YomiOnoBot> Floor 5 consists of Sunomata into Imagawa Yoshimoto
Simple as you like. This part is not super important, except insofar as it gives people something to type in chat.
What is a lot cooler to me is the underlying functionality, specifically the NillaryCommand and UnaryCommand classes that allows rapid addition of new commands to the bot:
struct NilaryCommand: Command {
let name: String
let impl: (_ context: LexieBot, _ caller: IRCUserID, _ target: IRCChannelName) -> ()
func call(context: LexieBot, caller: IRCUserID, target: IRCChannelName, module: any CommandModule, name: any StringProtocol, argstr: (any StringProtocol)? = nil) {
impl(context, caller, target)
}
}
struct UnaryCommand<ArgumentType>: Command where ArgumentType: LosslessStringConvertible {
let name: String
let impl: (_ context: LexieBot, _ caller: IRCUserID, _ target: IRCChannelName, _ argument: ArgumentType) -> ()
func call(context: LexieBot, caller: IRCUserID, target: IRCChannelName, module: any CommandModule, name: any StringProtocol, argstr: (any StringProtocol)?) {
guard
let argument = argstr
.map({ $0.trimmingCharacters(in: .whitespacesAndNewlines) })
.flatMap({ ArgumentType(String($0)) })
else {
context.say(
context.ircClient,
target,
message: "Invalid argument to command, see !\(module.name)-help for info."
)
return
}
impl(context, caller, target, argument)
}
}
