[Linux-only] basically bloxstap for sober

update

+41 -18
+1
package.json
··· 5 5 "main": "src/index.ts", 6 6 "scripts": { 7 7 "dev": "bun src/index.ts --gamemode --use-features \"wayland-copy,regretevator-notifications,hyprland-ipc,regretevator-waybar\"", 8 + "dev-opengl": "bun src/index.ts --gamemode --opengl --use-features \"wayland-copy,regretevator-notifications,hyprland-ipc,regretevator-waybar\"", 8 9 "build": "mkdir -p dist && bun build --minify --compile src/ --outfile dist/tuxstrap" 9 10 }, 10 11 "repository": {
+10 -4
src/features/regretevator-notifications.ts
··· 3 3 import { exec } from "child_process"; 4 4 import { GetPlaceDetails, GetUniverseId } from "../lib/RobloxAPI"; 5 5 6 + let regretevator: boolean = false; 7 + 6 8 PluginEventEmitter.on("SetRichPresence",async(data: any)=>{ 7 - const isRegretevator = (await GetUniverseId(activityWatcher.ActivityPlaceId)) == (await GetUniverseId(4972273297)); 9 + const isRegretevator = (await GetUniverseId(activityWatcher.ActivityPlaceId)) === (await GetUniverseId(4972273297)); 8 10 // console.log("IsRegretevator",isRegretevator,data) 9 11 if (isRegretevator) { 12 + if (!regretevator) { 13 + regretevator = true; 14 + exec(`notify-send -a "tuxstrap" -u low "Regretevator" "???????"`); 15 + } 10 16 try { 11 17 if (bloxstraprpc._stashedRPCMessage?.largeImage?.hoverText === "THE REGRET ELEVATOR" && bloxstraprpc._stashedRPCMessage?.smallImage?.hoverText === "The Axolotl Sun") { 12 18 if ((data.state as string).match(/^On Floor ([0-9]+)$/)) { ··· 15 21 } else if ((data.state as string) === "Going up!") { 16 22 exec(`notify-send -a "tuxstrap" -u low "Regretevator" "Going Up!"`); 17 23 } else if ((data.state as string) === "Lounging in the lobby") { 18 - exec(`notify-send -a "tuxstrap" -u low "Regretevator" "u dead lol"`); 24 + exec(`notify-send -a "tuxstrap" -u low "Regretevator" "cmon, just one more floor pleaseeeeeee :3"`); 19 25 } 20 26 } 21 27 } catch(e_) {} 28 + } else { 29 + regretevator = false; 22 30 } 23 31 }) 24 - 25 - if (activityWatcher.options.showNotifications) exec(`notify-send -a "tuxstrap" -u low "Roblox" "Loaded: Regretevator Notifications"`);
+19 -7
src/features/regretevator-waybar.ts
··· 9 9 writeFileSync(`${homedir()}/.regretevator_state`,data) 10 10 } 11 11 12 + let isInitalLaunch = true; 13 + let lastFloorNum = "0"; 14 + 12 15 activityWatcher.BloxstrapRPCEvent.on("OnGameLeave",()=>{ 16 + isInitalLaunch = true; 17 + lastFloorNum = "0"; 13 18 try { 14 19 rmSync(`${homedir()}/.regretevator_state`); 15 20 } catch {}; 16 21 }) 22 + 17 23 18 24 PluginEventEmitter.on("SetRichPresence",async(data: any)=>{ 19 25 const isRegretevator = (await GetUniverseId(activityWatcher.ActivityPlaceId)) == (await GetUniverseId(4972273297)); ··· 23 29 if (bloxstraprpc._stashedRPCMessage?.largeImage?.hoverText === "THE REGRET ELEVATOR" && bloxstraprpc._stashedRPCMessage?.smallImage?.hoverText === "The Axolotl Sun") { 24 30 if ((data.state as string).match(/^On Floor ([0-9]+)$/)) { 25 31 const f = (data.state as string).replace(/[a-zA-Z ]*/g,''); 26 - writeState(`ý ${f}`); 32 + lastFloorNum = f; 33 + writeState(`{"text":"ý ${f}","tooltip":"On Floor ${f}"}`); 27 34 } else if ((data.state as string).match(/^Currently spectating (.*)$/)) { 28 35 const f = (data.state as string).replace(/^Currently spectating /g,''); 29 - writeState(`ý ${f}`); 36 + // let nextFloorNum = "0"; 37 + // try { nextFloorNum = Number(lastFloorNum)+1 } catch {}; 38 + writeState(`{"text":"ý ${f}","tooltip":"Spectating ${f}"}`); 30 39 } else if ((data.state as string) === "Going up!") { 31 - writeState(`ý `); 40 + writeState(`{"text":"ý ","tooltip":"Floor ${lastFloorNum}  ${Number(lastFloorNum)+1}"}`); 32 41 } else if ((data.state as string) === "Lounging in the lobby") { 33 - writeState(`ý 󰱮`); 42 + writeState(`{"text":"ý ","tooltip":"In Lobby"}`); 34 43 } else { 35 - writeState(`ý`); 44 + if (isInitalLaunch) { 45 + isInitalLaunch = false; 46 + writeState(`{"text":"ý","tooltip":"Playing Regretevator"}`); 47 + } else { 48 + writeState(`{"text":"ý ","tooltip":"Floor ${lastFloorNum}  ${Number(lastFloorNum)+1}"}`); 49 + } 36 50 } 37 51 } 38 52 } catch(e_) {} 39 53 } 40 54 }) 41 - 42 - if (activityWatcher.options.showNotifications) exec(`notify-send -a "tuxstrap" -u low "Roblox" "Loaded: Regretevator Waybar (OCbwoy3's Dotfiles)"`);
-2
src/features/wayland-copy.ts
··· 14 14 if (activityWatcher.options.showNotifications) exec(`notify-send -i ${path.join(__dirname,"..","assets/roblox.png")} -u low "Roblox" "${gmfixed} wrote to the Wayland clipboard!"`); 15 15 } 16 16 }) 17 - 18 - if (activityWatcher.options.showNotifications) exec(`notify-send -a "tuxstrap" -u low "Roblox" "Loaded: Wayland Clipboard"`);
+9 -5
src/index.ts
··· 1 1 import { Command } from "commander"; 2 2 import { textSync } from "figlet"; 3 - import { LAUNCH_COMMAND, setActivityWatcherInstance, setBloxstrapRPCInstance, TUXSTRAP_VERSION } from "./lib/Constants"; 3 + import { activityWatcher, LAUNCH_COMMAND, setActivityWatcherInstance, setBloxstrapRPCInstance, TUXSTRAP_VERSION } from "./lib/Constants"; 4 4 import { exec, spawn } from "child_process"; 5 5 import { ActivityWatcher } from "./lib/ActivityWatcher"; 6 6 import { TuxstrapOptions } from "./lib/Types"; ··· 20 20 .option("-s, --silent", "Disable game join and plugin notifications") 21 21 .option("-v, --verbose", "Shows Roblox's stdout in the log") 22 22 .option("--background", "Runs the process in the background") 23 + .option("--opengl", "Use the OpenGL renderer instead of Vulkan") 23 24 .argument('[url]','A roblox:// URL for launching a specific game or server (optional)') 24 25 25 26 program.addHelpText('after',` ··· 57 58 if (options.verbose === true) { opts.verbose = true }; 58 59 59 60 const URI = program.args[0] || "roblox://"; 60 - const sober_cmd = `${opts.useGamemode ? "gamemoderun " : ""}${LAUNCH_COMMAND}${program.args[0] ? ` "${URI}"` : ""}` 61 + const sober_cmd = `${opts.useGamemode ? "gamemoderun " : ""}${LAUNCH_COMMAND}${program.args[0] ? ` "${URI}"` : ""}${options.opengl ? " --opengl" : ""}` 61 62 62 63 if (options.background) { 63 64 console.log("[INIT]","Process argv:",process.argv.join(" ")); ··· 73 74 74 75 console.log("[INIT]","Using features:",opts.useFeatures); 75 76 console.log("[INIT]","Sober Launch Command:",sober_cmd); 77 + 78 + if (options.opengl) exec(`notify-send -a "tuxstrap" -u low "Roblox" "Using OpenGL renderer"`); 76 79 77 80 const launch_time = Date.now(); 78 81 const child = exec(sober_cmd); 79 82 83 + 80 84 const watcher = new ActivityWatcher(child,opts); 81 85 setActivityWatcherInstance(watcher); 82 86 ··· 115 119 })() 116 120 117 121 if (opts.showNotifications) { 118 - setTimeout(() => { 119 - exec(`notify-send -a "tuxstrap" -u low "Roblox" "Hello, World!"`); 120 - }, 1000); 122 + activityWatcher.BloxstrapRPCEvent.on("ObtainLog",()=>{ 123 + exec(`notify-send -a tuxstrap -u low "TuxStrap" "Obtained Roblox's logfile"`); 124 + }) 121 125 } 122 126 123 127 watcher.stdoutWatcher();
+2
src/lib/ActivityWatcher.ts
··· 244 244 const logHandle = await open(robloxLogfile,'r+'); 245 245 console.log("[ActivityWatcher]",`Obtained r+ logfile handle: ${robloxLogfile}`) 246 246 247 + this.BloxstrapRPCEvent.emit("ObtainLog") 248 + 247 249 try { 248 250 let position = 0; 249 251 let line = ""