Skip to content

Events ​

The Events namespace provides access to the game's event system. Listen to in-game events (terminal commands, file operations, network activity), emit events to the game engine, and communicate between mods using custom events.

Required permission: events

Import ​

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

Methods ​

Events.on(event, callback) ​

Listen to a game event or a custom mod event. Returns an unsubscribe function.

ParameterTypeDescription
eventstringEvent name (game event or custom event)
callback(data) => voidHandler function

Returns: () => void - call to unsubscribe

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

// Later: stop listening
unsub();

Events.off(event, callback) ​

Remove a specific event listener by reference.

typescript
function handler(data: any) { /* ... */ }
Events.on("Terminal.NmapScan", handler);
Events.off("Terminal.NmapScan", handler);

Events.emit(event, data?) ​

Emit an event. Behavior depends on the event name:

  • Known game events (e.g. Terminal.NmapScan, Bank.Transfer) - dispatched to both the game event bus and the custom event bus.
  • Custom/unknown events (e.g. MyMod.BossDefeated) - dispatched only to the custom event bus, enabling cross-mod communication without polluting game internals.
typescript
// Custom event - goes to other mods only
Events.emit("MyMod.BossDefeated", { bossName: "Hydra", reward: 500 });

// Known game event - also triggers game engine listeners
Events.emit("Terminal.NmapScan", { ip: "10.0.0.1" });

Events.register(name) ​

Register a custom event name for cross-mod communication. Optional but recommended for discoverability.

typescript
Events.register("MyMod.BossDefeated");
Events.register("MyMod.LevelUp");

Game Events ​

These are built-in events emitted by the game engine. Use them in Events.on() to react to player actions.

The Events guide lists all 99 of them. The SDK's ModEventMap type is the authoritative, fully-typed source, so your editor infers the exact payload from the event name. A sample:

Terminal Events ​

EventDataDescription
Terminal.NmapScanNmapScanEventPlayer ran nmap on an IP
Terminal.SSH.Connectedstring (connected server IP)Player connected via SSH
Terminal.SSH.Disconnectedstring (disconnected server IP)Player disconnected from SSH
Terminal.CommandTerminalCommandEventAny terminal command executed
Terminal.WhoisWhoisEventPlayer ran whois

File Events ​

EventDataDescription
Files.OpenFileOpenEventA file was opened
Files.TransferFileTransferEventA file was downloaded / transferred
Files.DeletedFileInfoA file was deleted

Network Events ​

EventDataDescription
Network.PortChangesNetworkPortChangesEventA machine's ports changed ({ subnet, oldPorts, newPorts })
Network.UserActivityNetworkUserActivityEventUser went online/offline
Network.WifiConnectedNetworkSubnetInfoConnected to WiFi (the whole router)
Network.WifiDisconnectednullLeft the current WiFi network

WeeChat Events ​

EventDataDescription
WeeChat.Connectedstring (IRC host)Joined an IRC server
WeeChat.MessageWeeChatMessageEventMessage sent in WeeChat

Not every payload is an object

Several events hand over a bare string, boolean, null or undefined, and a few hand over the engine's own object with PascalCase fields. Destructuring those gets you nothing. See Not every payload is an object.

Type-Safe Custom Events ​

You can extend the ModEventMap interface to get full type safety for your custom events. Use TypeScript's declaration merging:

typescript
declare module "@hotbunny/hackhub-content-sdk" {
    interface ModEventMap {
        "MyMod.BossDefeated": { bossName: string; reward: number };
        "MyMod.LevelUp": { level: number; xp: number };
    }
}

After this declaration, Events.on() and Events.emit() provide full type inference for your custom events:

typescript
// Fully typed - data is { bossName: string; reward: number }
Events.on("MyMod.BossDefeated", (data) => {
    console.log(`${data.bossName} defeated! Reward: $${data.reward}`);
});

// Type error if payload doesn't match
Events.emit("MyMod.LevelUp", { level: 5, xp: 1200 });

You can place the declare module block anywhere in your project (e.g. in a types.d.ts file or at the top of your main index.ts).

Cross-Mod Communication ​

Mods can communicate by emitting and listening to custom events:

typescript
// Mod A: Register and emit
Events.register("ModA.DataReady");
Events.emit("ModA.DataReady", { items: ["sword", "shield"] });

// Mod B: Listen
Events.on("ModA.DataReady", (data) => {
    console.log("Mod A shared:", data.items);
});

Quest Events (Scoped) ​

Inside a Quest class, use this.Events.on() instead of the global Events.on(). Scoped listeners are automatically cleaned up when the quest completes or is abandoned.

Register them in OnObjectivesStart() (runs on claim and on every game start), not OnStart() (runs once at claim). Listeners are lost on reload, and only OnObjectivesStart() re-attaches them:

typescript
class MyQuest extends Quest {
    // Runs on claim and on every game start, so listeners survive reloads.
    OnObjectivesStart() {
        this.Events.on("Terminal.NmapScan", (data) => {
            if (data.ip === "192.168.1.50") {
                this.completeObjective("scan");
            }
        });
    }
}

HotBunny Interactive Entertainment Inc.