Skip to content

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:

typescript
import { Events } from "@hotbunny/hackhub-content-sdk";

Events.on("Terminal.NmapScan", (data) => {
    console.log(`Player scanned ${data.ip}`);
});

Events.on() returns an unsubscribe function:

typescript
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.

typescript
@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:

typescript
Events.emit("MyMod.ScoreUpdated", { score: 100 });

Events.on("MyMod.ScoreUpdated", (data) => {
    console.log(`Score: ${data.score}`);
});

You can optionally register event names for discoverability:

typescript
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:

typescript
// 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 ​

EventPayload
Game.SessionStartednone (undefined)

Terminal ​

EventPayload
Terminal.CommandTerminalCommandEvent
Terminal.NmapScanNmapScanEvent
Terminal.NslookupNslookupEvent
Terminal.PingPingEvent
Terminal.InstallPackageTerminalInstallPackageEvent
Terminal.CdTerminalCdEvent ({ from, to }, both files)
Terminal.LsFileInfo (the folder that was listed)
Terminal.CatFileInfo (the file that was read)
Terminal.ExplorerExplorerEvent
Terminal.OpensslTerminalOpensslEvent ({ type, input, output })
Terminal.IfconfigTerminalIfconfigEvent
Terminal.Geoipstring (the looked-up target)

Recon & Lookup ​

EventPayload
Terminal.WhoisWhoisEvent
Terminal.DigDigEvent
Terminal.DirhunterDirhunterEvent
Terminal.MxlookupTerminalMxlookupEvent
Terminal.DnsHistoryTerminalDnsHistoryEvent (multiplayer only)
Terminal.Lynx.Searchstring (the search term)
Terminal.Lynx.LookupTerminalLynxLookupEvent ({ input, data })
Subfinder.Trystring (the domain)
Subfinder.ResultsSubfinderResultsEvent
Nuclei.ItemNucleiItemEvent ({ file, currentDomain })
Nuclei.ResultsNucleiResultsEvent

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 ​

EventPayload
Terminal.SSH.Connectedstring (connected server IP)
Terminal.SSH.Disconnectedstring (disconnected server IP)
Terminal.SSH.Shutdownstring (the host)
Terminal.SSH.FileDownloadFileInfo
Terminal.FTP.Connectstring (the host)
RemoteConnection.EstablishedRemoteConnectionEvent (match on targetIp)
RemoteConnection.DisconnectedRemoteConnectionEvent

Cracking ​

EventPayload
Terminal.Hydra.TryTerminalHydraTryEvent (started; no credentials yet)
Terminal.HydraHydraEvent (succeeded; carries credentials)
HashcatFileInfo (the file that was cracked)
John.DecryptHashJohnDecryptHashEvent
Fern.FindPasswordFernFindPasswordEvent

Exploitation ​

EventPayload
Metasploit.Msfconsolenone (undefined)
Metasploit.SearchMetasploitSearchEvent
Metasploit.UseMetasploitModuleInfo
Metasploit.ShowOptionsMetasploitModuleInfo
Metasploit.SetOptionMetasploitSetOptionEvent
Metasploit.EventMetasploitEvent ({ name, module, data })
Metasploit.Event.TryMetasploitEvent
Metasploit.RootgrabMetasploitRootgrabEvent
Metasploit.Meterpreter.ConnectedMeterpreterConnectedEvent (the session)
Meterpreter.DownloadMeterpreterDownloadEvent
Sqlmap.ListTablesSqlmapListTablesEvent
Sqlmap.DumpTableSqlmapDumpTableEvent

Bettercap ​

None of these carry a payload except NetProbe.

EventPayload
Bettercap.Opennull
Bettercap.Closenull
Bettercap.NetProbeboolean (whether probing is now on)
Bettercap.NetShownull
Bettercap.WifiReconnull
Bettercap.WifiDeAuthnull

Network ​

EventPayload
Network.PortChangesNetworkPortChangesEvent ({ subnet, oldPorts, newPorts })
Network.UserActivityNetworkUserActivityEvent
Network.WifiConnectedNetworkSubnetInfo (the whole router)
Network.WifiDisconnectednull
NetworkPacketTransferNetworkPacketTransferEvent
PFSense.LoginPFSenseLoginEvent
PFSense.ChangesPFSenseChangesEvent
Wireshark.StartedWiresharkListeningEvent ({ source?, destination? })
Wireshark.StoppedWiresharkListeningEvent

Files & Processes ​

EventPayload
Files.OpenFileOpenEvent
Files.TransferFileTransferEvent
Files.DeletedFileInfo
Process.KilledProcessKilledEvent (pid is a string)
Python3.ExecFilePython3ExecFileEvent

Browser & HTTP ​

EventPayload
Browser.WebsiteOpenedBrowserWebsiteOpenedEvent (PascalCase: SiteName, Url)
Browser.MetaBrowserMetaEvent (parsed URL of the opened page)
Http.RequestHttpRequest
Http.ResponseHttpTransaction
Http.InterceptedHttpRequest
Http.CollaboratorHitCollaboratorHit
BCC.News.Openedstring (article id)
AppStore.Downloadedstring (app name)

See the Http API for serving hosts that raise these.

Database ​

EventPayload
Database.ConnectedDatabaseConnectedEvent (address is host)
Database.DataUpdateDatabaseDataUpdateEvent

Communication ​

EventPayload
Mail.ReceivedMailEvent
Mail.SentMailEvent
Mail.ReadMailEvent
Mail.MailboxOpenedMailMailboxOpenedEvent (not reshaped; no flat subject)
Mail.AccountCreatedMailAccountEvent
Mail.AccountLoggedInMailAccountEvent
Kisscord.FriendAddedKisscordFriendAddedEvent
Kisscord.MessagingKisscordMessagingEvent
WeeChat.Connectedstring (IRC host)
WeeChat.Disconnectedstring (IRC host)
WeeChat.MessageWeeChatMessageEvent

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 ​

EventPayload
Twotter.AccountCreatedTwotterAccountCreatedEvent
Twotter.AccountLoginTwotterAccountLoginEvent
Twotter.AccountLogoutTwotterAccountLogoutEvent
Twotter.PostSeenTwotterPostSeenEvent
Twotter.PostTwotterPostEvent
Twotter.ProfileSeenTwotterProfileSeenEvent

Bank & Quests ​

EventPayload
Bank.TransferBankTransferEvent (from is an object; read from.IBAN)
Bank.AccountCreatedBankAccountEvent
Bank.LogoutBankAccountEvent
Quest.ClaimedQuestClaimedEvent (PascalCase: Id, Name, Title)

INFO

Requires the events permission in your manifest.json.

HotBunny Interactive Entertainment Inc.