openrbx
Version:
CLI tool to launch Roblox Studio with place and universe IDs
151 lines (131 loc) • 4.74 kB
text/typescript
import { Command } from "commander";
import packageJson from "../package.json";
import { platform } from "os";
import { exec } from "child_process";
import { promisify } from "util";
import open from "open";
// execAsync is a promisified version of the exec function from child_process,
// allowing to use async/await syntax for running shell commands.
const execAsync = promisify(exec);
async function checkExistingProcesses(
noLogs: boolean = false
): Promise<boolean> {
try {
const currentPlatform = platform();
let command: string;
switch (currentPlatform) {
case "win32":
command =
'tasklist /fi "imagename eq RobloxStudioBeta.exe" /fo csv | find /c "RobloxStudioBeta.exe"';
break;
case "darwin":
command = 'pgrep -f "RobloxStudio" | wc -l';
break;
case "linux":
command = 'pgrep -f "roblox-studio" | wc -l';
break;
default:
if (!noLogs) {
console.warn(
`Process checking not supported on platform: ${currentPlatform}`
);
}
return false;
}
const { stdout } = await execAsync(command);
const processCount = parseInt(stdout.trim());
if (process.env.DEBUG) {
console.log(`🔍 Found ${processCount} Roblox Studio processes`);
}
return processCount > 0;
} catch (error) {
if (process.env.DEBUG) {
console.warn("Warning: Could not check for existing processes:", error);
}
return false;
}
}
function buildProtocolUrl(option: any): string {
const baseUrl = "roblox-studio:1";
const allParams = {
launchmode: option.mode,
task: option.task,
placeId: option.placeId,
universeId: option.universeId,
};
const paramString = Object.entries(allParams)
.map(([key, value]) => `${key}:${value}`)
.join("+");
return `${baseUrl}+${paramString}`;
}
async function main() {
const program = new Command();
program
.name("openrbx")
.description("🚀 OpenRBX - Roblox Studio Launcher")
.version(packageJson.version)
.option("-p, --place-id <id>", "Place ID (required)")
.option("-u, --universe-id <id>", "Universe ID (required)")
.option("-m, --mode <mode>", "Launch mode", "edit")
.option("-t, --task <task>", "Task to execute", "EditPlace")
.option("--multiple-process", "Allow multiple Roblox Studio instances")
.option("--no-logs", "Show only essential logs")
.action(async (options) => {
try {
const protocolUrl = buildProtocolUrl(options);
const logs = !options.logs; // Invert logs option because we want to hide logs when --no-logs is set
if (!logs) {
console.log("Launching Roblox Studio:");
console.log(` - 📍 Place ID: ${options.placeId}`);
console.log(` - 🌌 Universe ID: ${options.universeId}`);
console.log(` - ⚙️ Mode: ${options.mode}`);
console.log(` - 📋 Task: ${options.task}`);
console.log(` - 🔗 Protocol URL: ${protocolUrl}`);
}
// Check for existing processes unless multiple-process is enabled
if (!options["multiple-process"]) {
if (!logs) {
console.log("🔍 Checking for existing Roblox Studio processes...");
}
const hasExistingProcesses = await checkExistingProcesses(logs);
if (hasExistingProcesses) {
console.log("⚠️ Warning: Roblox Studio is already running");
if (!logs) {
console.log(
"💡 Use --multiple-process to allow multiple instances"
);
}
console.log("❌ Aborting launch to prevent conflicts");
process.exit(1);
} else {
if (!logs) {
console.log("✅ No existing Roblox Studio processes found");
}
}
} else {
if (!logs) {
console.log(
"🔄 Multiple process mode enabled - skipping process check"
);
}
}
open(protocolUrl);
console.log("✅ Roblox Studio launched successfully!");
} catch (error) {
if (error instanceof Error) {
if (
"code" in error &&
error.code === "ERR_PARSE_ARGS_UNKNOWN_OPTION"
) {
console.error(
"❌ Unknown option provided. Use --help to see available options."
);
} else {
console.error("❌ Error:", error);
}
}
}
});
program.parse();
}
main();