@hotbunny/hackhub-content-sdk
v0.10.0
Published
Official modding SDK for HackHub - Ultimate Hacker Simulator on Steam. Create custom quests, websites, terminal commands, and desktop apps.
Maintainers
Readme
@hotbunny/hackhub-content-sdk
Official modding SDK for HackHub - Ultimate Hacker Simulator on Steam. Create custom quests, websites, terminal commands, desktop apps, and more.
Getting Started
Create a New Mod
npm create hackhub-modThe CLI scaffolds a complete mod project with build config, templates, and TypeScript support.
Manual Setup
npm install @hotbunny/hackhub-content-sdk --save-devMod Entry Point
Every mod needs a Bootstrap class decorated with @RegisterModPackage:
import { Bootstrap, RegisterModPackage } from "@hotbunny/hackhub-content-sdk";
@RegisterModPackage
export default class MyMod extends Bootstrap {
OnModPackageLoaded() {
console.log("Mod loaded!");
}
OnModPackageUnloaded() {
console.log("Mod unloaded");
}
}Quests
Quests use a generic type parameter for type-safe data. CreateData() initializes the data once when the quest is first claimed. After that, access via this.Data and update via this.SetData():
import { Quest, Network, RegisterQuest } from "@hotbunny/hackhub-content-sdk";
interface InfiltrationData {
targetIp: string;
attempts: number;
}
@RegisterQuest
class InfiltrationQuest extends Quest<InfiltrationData> {
Name = "Infiltration";
Title = "Server Infiltration";
Description = "Hack into the target server and download the data.";
Rewards = { money: 5000, xp: 200 };
Objectives = [
{ name: "scan", description: "Scan the target server" },
{
name: "connect",
description: "Connect via SSH",
unlocksAfter: ["scan"],
},
];
CreateData(): InfiltrationData {
return {
targetIp: Network.randomIp(),
attempts: 0,
};
}
OnStart() {
Network.createSubnetNetwork({
ip: this.Data.targetIp,
type: "ROUTER",
ports: [{ external: 22, internal: 22, active: true, service: "ssh" }],
users: [Network.createUser({ username: "admin", password: "secret123" })],
children: [],
});
this.Events.on("Terminal.NmapScan", (data) => {
if (data.ip === this.Data.targetIp) {
this.SetData("attempts", this.Data.attempts + 1);
this.completeObjective("scan");
}
});
this.Events.on("Terminal.SSH.Connected", (data) => {
if (data.ip === this.Data.targetIp) this.completeObjective("connect");
});
}
OnComplete() {
Network.destroyNetwork(this.Data.targetIp);
}
}Quest Mail & Dialogs
Quests can send in-game emails and start phone call dialogs:
@RegisterQuest
class StoryQuest extends Quest<{ contacted: boolean }> {
Name = "StoryQuest";
Title = "Story Quest";
Objectives = [{ name: "start", description: "Begin the mission" }];
Mails = [
{ title: "Mission Briefing", content: "Your target is ready. Good luck." },
];
Dialog = {
default: [
{ speaker: "Handler", text: "Are you ready for the mission?", options: [
{ label: "Yes", text: "I'm ready.", switchBranch: "briefing" },
{ label: "No", text: "Not yet.", isEnd: true },
]},
],
briefing: [
{ speaker: "Handler", text: "Good luck out there.", isEnd: true },
],
};
CreateData() {
return { contacted: false };
}
OnStart() {
this.sendMail(0);
this.createDialog("default");
}
}Websites
Websites use a Pages array. Each page has a path, title, and an html file rendered inside the in-game browser:
import { Website, RegisterWebsite } from "@hotbunny/hackhub-content-sdk";
@RegisterWebsite
class HackerForum extends Website {
SiteName = "Hacker Forum";
Host = "hackerforum.net";
Icon = "./assets/forum-icon.png";
Pages = [
{ path: "/", title: "Home", html: "pages/home.html" },
{ path: "/about", title: "About", html: "pages/about.html" },
];
}You can expose TypeScript functions to your HTML pages via Exports:
@RegisterWebsite
class MyWebsite extends Website {
SiteName = "My Site";
Host = "mysite.com";
Icon = "./assets/icon.png";
Pages = [
{ path: "/", title: "Home", html: "pages/home.html" },
];
Exports = {
formatPost: (text: string) => text.toUpperCase(),
};
}In your HTML, exported functions are available as globals and SDK APIs via HackhubSDK:
<script>
const formatted = formatPost("hello");
HackhubSDK.Mail.send({ to: "[email protected]", subject: "Hi" });
</script>Terminal Commands
import { Command, RegisterCommand } from "@hotbunny/hackhub-content-sdk";
@RegisterCommand
class PingCommand extends Command {
CommandName = "myping";
Description = "Custom ping command";
async Run(tools) {
const args = tools.getArgs();
if (args.length === 0) {
tools.printError("Usage: myping <ip>");
return;
}
tools.println(`Pinging ${args[0]}...`);
await tools.sleep(1000);
tools.println("Reply received.");
}
}Desktop Apps
import { App, RegisterApp } from "@hotbunny/hackhub-content-sdk";
@RegisterApp
class MyApp extends App {
AppName = "mytool";
Title = "My Tool";
Icon = "./assets/app-icon.png";
HTML = "app.html";
DefaultSize = { width: 600, height: 400 };
}Apps can have an App Store listing and expose functions to HTML, just like websites:
@RegisterApp
class PasswordGen extends App {
AppName = "passgen";
Title = "Password Generator";
Icon = "./assets/passgen.png";
HTML = "app.html";
DefaultSize = { width: 400, height: 300 };
Unlocked = true;
Store = {
title: "Password Generator",
ratings: 4.5,
description: "Generate secure passwords",
};
Exports = {
generate: (length: number) => Random.password(),
};
}Mod Settings
Players can configure your mod from the in-game Mods menu. Use the ModSettings API to read and write setting values:
import { Bootstrap, ModSettingDefinition, ModSettings, RegisterModPackage } from "@hotbunny/hackhub-content-sdk";
@RegisterModPackage
export default class MyMod extends Bootstrap {
Settings: ModSettingDefinition[] = [
{
key: "difficulty",
label: "Difficulty",
type: "select",
default: "normal",
options: [
{ label: "Easy", value: "easy" },
{ label: "Normal", value: "normal" },
{ label: "Hard", value: "hard" },
],
},
{ key: "showHints", label: "Show Hints", type: "toggle", default: true },
{ key: "maxEnemies", label: "Max Enemies", type: "slider", default: 5, min: 1, max: 20 },
];
OnModPackageLoaded() {
const difficulty = ModSettings.get<string>("difficulty");
const hints = ModSettings.get<boolean>("showHints");
console.log(`Difficulty: ${difficulty}, Hints: ${hints}`);
}
}Available setting types: toggle, select, text, number, slider.
For fully custom settings panels, use an HTML file rendered in iframe:
@RegisterModPackage
export default class MyMod extends Bootstrap {
SettingsHTML = "settings.html";
}API Reference
Namespaces
| Namespace | Purpose |
|-----------|---------|
| Events | Listen to 60+ game events, emit custom events |
| Files | Create, read, write, delete in-game files |
| Network | Create networks, ports, firewalls, domains |
| Mail | Send in-game emails |
| Bank | Bank accounts and transactions |
| Random | Random generation (id, password, username, pick, etc.) |
| ModSettings | Read/write mod settings configured by the player |
| Storage | Persistent key-value storage per mod |
| Variables | Session-only variables (reset on game close) |
| SharedStorage | Persistent storage shared between mods |
| SharedVariables | Session variables shared between mods |
| Shell | Execute terminal commands programmatically |
| UI | Notifications and toasts |
| Twotter | In-game social media (Twitter-like) |
| Kisscord | In-game messaging (Discord-like) |
| WeeChat | In-game IRC chat |
Random
import { Random } from "@hotbunny/hackhub-content-sdk";
Random.id(); // Short unique ID
Random.uuid(); // UUID v4
Random.number(1, 100); // Random integer 1-100
Random.password(); // Random password
Random.username(); // Random username
Random.pick(["a", "b", "c"]); // Random array element
Random.pickMultiple(arr, 3); // 3 unique random elements
await Random.sleep(2000); // Wait 2 secondsModSettings
import { ModSettings } from "@hotbunny/hackhub-content-sdk";
ModSettings.get<string>("difficulty"); // Read a setting value
ModSettings.getAll(); // All settings as key-value map
ModSettings.set("difficulty", "hard"); // Write a setting value
ModSettings.reset("difficulty"); // Reset to default
ModSettings.resetAll(); // Reset all to defaultsEvents
import { Events } from "@hotbunny/hackhub-content-sdk";
// Listen to game events
Events.on("Terminal.NmapScan", (data) => console.log(`Scanned ${data.ip}`));
Events.on("Bettercap.Open", () => console.log("Bettercap opened"));
Events.on("Process.Killed", (data) => console.log(`Killed ${data.name}`));
// Custom cross-mod events
Events.emit("MyMod.ScoreUpdated", { score: 100 });
Events.on("MyMod.ScoreUpdated", (data) => console.log(data.score));Manifest
Each mod requires a manifest.json in its root:
{
"id": "my-mod-id",
"name": "My Mod",
"version": "1.0.0",
"author": "Your Name",
"description": "A brief description of the mod",
"apiVersion": 1,
"permissions": ["filesystem", "network", "events"],
"cover": "cover.png",
"tags": ["quest", "network"]
}Permissions
| Permission | Grants access to |
|------------|-----------------|
| filesystem | Files API |
| network | Network API |
| events | Events API |
| mail | Mail API |
| bank | Bank API |
| shell | Shell API |
| ui | UI API |
Steam Workshop
Mods support Steam Workshop for easy distribution:
- Upload local mods to Workshop from the in-game Mods menu
- Subscribe to mods on Workshop -- they're automatically downloaded and loaded
- Update published mods with change notes
Links
License
MIT
