Events
The Events system lets mods listen to 99 game events and emit custom cross-mod events.
Global Events
Use the Events namespace for mod-level event listening:
import { Events } from "@hotbunny/hackhub-content-sdk";
Events.on("Terminal.NmapScan", (data) => {
console.log(`Player scanned ${data.ip}`);
});Events.on() returns an unsubscribe function:
const unsub = Events.on("Terminal.Ping", (data) => {
console.log(`Pinged ${data.ip}`);
});
// later...
unsub();Quest-Scoped Events
Inside quests, always use this.Events instead of the global Events. Listeners registered through this.Events are automatically cleaned up when the quest completes or is abandoned.
Register them in OnObjectivesStart() (runs on every game start), not OnStart() (runs once at claim). Listeners are lost on reload and only OnObjectivesStart() re-attaches them.
@RegisterQuest
class MyQuest extends Quest {
// ...
// Runs on claim and on every game start, so listeners survive reloads.
OnObjectivesStart() {
this.Events.on("Terminal.NmapScan", (data) => {
// re-attached on every game start;
// automatically removed on complete/abandon
});
}
}See the Quests guide for more details.
Custom Events
Emit and listen to custom events for cross-mod communication:
Events.emit("MyMod.ScoreUpdated", { score: 100 });
Events.on("MyMod.ScoreUpdated", (data) => {
console.log(`Score: ${data.score}`);
});You can optionally register event names for discoverability:
Events.register("MyMod.ScoreUpdated");Not every payload is an object
Some events hand over a bare primitive rather than a wrapper object. Destructuring one of those gets you nothing, so check the payload column before writing a listener:
// Right: the payload IS the host.
Events.on("Terminal.SSH.Connected", (ip) => {
if (ip === "10.40.0.12") { /* ... */ }
});
// Wrong: there is no `ip` property to read.
Events.on("Terminal.SSH.Connected", ({ ip }) => { /* undefined */ });Several payloads are also the engine's own objects, which means PascalCase fields (Quest.Claimed, Browser.WebsiteOpened) or a whole file (Terminal.Cat, Hashcat, Files.Deleted). The SDK's ModEventMap is the authoritative source for all of this, and your editor will infer the right shape from the event name.
TIP
If a check against a payload field never fires, the field probably does not exist. The SDK ships @deprecated markers on the interfaces that used to describe these payloads incorrectly, so hovering the type in your editor will say what to read instead.
Game Events Reference
Payloads are the SDK's exported interfaces. See the Event Map reference for the full type mapping, and Types for the interface fields.
Session
| Event | Payload |
|---|---|
Game.SessionStarted | none (undefined) |
Terminal
| Event | Payload |
|---|---|
Terminal.Command | TerminalCommandEvent |
Terminal.NmapScan | NmapScanEvent |
Terminal.Nslookup | NslookupEvent |
Terminal.Ping | PingEvent |
Terminal.InstallPackage | TerminalInstallPackageEvent |
Terminal.Cd | TerminalCdEvent ({ from, to }, both files) |
Terminal.Ls | FileInfo (the folder that was listed) |
Terminal.Cat | FileInfo (the file that was read) |
Terminal.Explorer | ExplorerEvent |
Terminal.Openssl | TerminalOpensslEvent ({ type, input, output }) |
Terminal.Ifconfig | TerminalIfconfigEvent |
Terminal.Geoip | string (the looked-up target) |
Recon & Lookup
| Event | Payload |
|---|---|
Terminal.Whois | WhoisEvent |
Terminal.Dig | DigEvent |
Terminal.Dirhunter | DirhunterEvent |
Terminal.Mxlookup | TerminalMxlookupEvent |
Terminal.DnsHistory | TerminalDnsHistoryEvent (multiplayer only) |
Terminal.Lynx.Search | string (the search term) |
Terminal.Lynx.Lookup | TerminalLynxLookupEvent ({ input, data }) |
Subfinder.Try | string (the domain) |
Subfinder.Results | SubfinderResultsEvent |
Nuclei.Item | NucleiItemEvent ({ file, currentDomain }) |
Nuclei.Results | NucleiResultsEvent |
Lynx resolves what the player typed
Terminal.Lynx.Lookup's input is the resolved subject, not the raw search. A player who looks someone up by their Twotter handle raises the event with that account's full name, so match on the name.
SSH & Remote Access
| Event | Payload |
|---|---|
Terminal.SSH.Connected | string (connected server IP) |
Terminal.SSH.Disconnected | string (disconnected server IP) |
Terminal.SSH.Shutdown | string (the host) |
Terminal.SSH.FileDownload | FileInfo |
Terminal.FTP.Connect | string (the host) |
RemoteConnection.Established | RemoteConnectionEvent (match on targetIp) |
RemoteConnection.Disconnected | RemoteConnectionEvent |
Cracking
| Event | Payload |
|---|---|
Terminal.Hydra.Try | TerminalHydraTryEvent (started; no credentials yet) |
Terminal.Hydra | HydraEvent (succeeded; carries credentials) |
Hashcat | FileInfo (the file that was cracked) |
John.DecryptHash | JohnDecryptHashEvent |
Fern.FindPassword | FernFindPasswordEvent |
Exploitation
| Event | Payload |
|---|---|
Metasploit.Msfconsole | none (undefined) |
Metasploit.Search | MetasploitSearchEvent |
Metasploit.Use | MetasploitModuleInfo |
Metasploit.ShowOptions | MetasploitModuleInfo |
Metasploit.SetOption | MetasploitSetOptionEvent |
Metasploit.Event | MetasploitEvent ({ name, module, data }) |
Metasploit.Event.Try | MetasploitEvent |
Metasploit.Rootgrab | MetasploitRootgrabEvent |
Metasploit.Meterpreter.Connected | MeterpreterConnectedEvent (the session) |
Meterpreter.Download | MeterpreterDownloadEvent |
Sqlmap.ListTables | SqlmapListTablesEvent |
Sqlmap.DumpTable | SqlmapDumpTableEvent |
Bettercap
None of these carry a payload except NetProbe.
| Event | Payload |
|---|---|
Bettercap.Open | null |
Bettercap.Close | null |
Bettercap.NetProbe | boolean (whether probing is now on) |
Bettercap.NetShow | null |
Bettercap.WifiRecon | null |
Bettercap.WifiDeAuth | null |
Network
| Event | Payload |
|---|---|
Network.PortChanges | NetworkPortChangesEvent ({ subnet, oldPorts, newPorts }) |
Network.UserActivity | NetworkUserActivityEvent |
Network.WifiConnected | NetworkSubnetInfo (the whole router) |
Network.WifiDisconnected | null |
NetworkPacketTransfer | NetworkPacketTransferEvent |
PFSense.Login | PFSenseLoginEvent |
PFSense.Changes | PFSenseChangesEvent |
Wireshark.Started | WiresharkListeningEvent ({ source?, destination? }) |
Wireshark.Stopped | WiresharkListeningEvent |
Files & Processes
| Event | Payload |
|---|---|
Files.Open | FileOpenEvent |
Files.Transfer | FileTransferEvent |
Files.Deleted | FileInfo |
Process.Killed | ProcessKilledEvent (pid is a string) |
Python3.ExecFile | Python3ExecFileEvent |
Browser & HTTP
| Event | Payload |
|---|---|
Browser.WebsiteOpened | BrowserWebsiteOpenedEvent (PascalCase: SiteName, Url) |
Browser.Meta | BrowserMetaEvent (parsed URL of the opened page) |
Http.Request | HttpRequest |
Http.Response | HttpTransaction |
Http.Intercepted | HttpRequest |
Http.CollaboratorHit | CollaboratorHit |
BCC.News.Opened | string (article id) |
AppStore.Downloaded | string (app name) |
See the Http API for serving hosts that raise these.
Database
| Event | Payload |
|---|---|
Database.Connected | DatabaseConnectedEvent (address is host) |
Database.DataUpdate | DatabaseDataUpdateEvent |
Communication
| Event | Payload |
|---|---|
Mail.Received | MailEvent |
Mail.Sent | MailEvent |
Mail.Read | MailEvent |
Mail.MailboxOpened | MailMailboxOpenedEvent (not reshaped; no flat subject) |
Mail.AccountCreated | MailAccountEvent |
Mail.AccountLoggedIn | MailAccountEvent |
Kisscord.FriendAdded | KisscordFriendAddedEvent |
Kisscord.Messaging | KisscordMessagingEvent |
WeeChat.Connected | string (IRC host) |
WeeChat.Disconnected | string (IRC host) |
WeeChat.Message | WeeChatMessageEvent |
Mail.Received, Mail.Sent and Mail.Read are flattened to a tidy MailEvent with subject and content. Mail.MailboxOpened is not: it hands over the engine's own mail object, where the subject lives inside content.
Social
| Event | Payload |
|---|---|
Twotter.AccountCreated | TwotterAccountCreatedEvent |
Twotter.AccountLogin | TwotterAccountLoginEvent |
Twotter.AccountLogout | TwotterAccountLogoutEvent |
Twotter.PostSeen | TwotterPostSeenEvent |
Twotter.Post | TwotterPostEvent |
Twotter.ProfileSeen | TwotterProfileSeenEvent |
Bank & Quests
| Event | Payload |
|---|---|
Bank.Transfer | BankTransferEvent (from is an object; read from.IBAN) |
Bank.AccountCreated | BankAccountEvent |
Bank.Logout | BankAccountEvent |
Quest.Claimed | QuestClaimedEvent (PascalCase: Id, Name, Title) |
INFO
Requires the events permission in your manifest.json.
