A command-line tool for analyzing Roblox .rbxm(x) model files to identify workspaces and detect hidden places embedded within them.
This tool works to detect Roblox workspaces within .rbxm(x) model files, which could potentially contain stolen/lost places. It runs on the Lune runtime environment.
lib/
├─ fileproc.luau : File and directory processing
├─ cli.luau : CLI argument parsing and usage
├─ core.luau : Core detection logic (workspace scanning, etc)
tests/
├─ containsworkspace/ : Test cases that should contain workspaces
├─ doesntcontainworkspace/ : Test cases that shouldn't contain workspaces
├─ zlibCompressed/ : Zlib compressed test casees
├─ binaryFiles/ : Extensionless/binary test cases
├─ tests.luau : Test runner for CI
detector.luau : Main entrypoint
Install the Lune runtime using rokit
Clone or download this repository and ensure all required libraries are installed:
git clone https://github.com/filoxen/workspace-detector.git
cd workspace-detector
rokit installlune run detector path/to/your/model.rbxm(x)lune run detector --directory /path/to/your/directory/with/modelslune run detector --output /path/to/your/output/file.txtlune run detector --force-binary-read /path/to/your/model.variantfilelune run detector --print-instance-names /path/to/your/model.rbxmlune run detector --zlib-decompress /path/to/your/model.rbxmlune run detector --zlib-decompress-recursive /path/to/your/model.rbxm- Requires valid .rbxm files (corrupted/invalid/different versioned files may cause errors)
Contributions are welcome. Please ensure new features include documentation. Follow existing code style to the best of your ability and try not to make breaking changes.
When adding new core functions that operate on files, please follow the existing convention:
(fileContents: string, opts: types.opts) -> string | booleanThis is for writing working tests. To write a new test, follow the example in tests.luau:
-- folderName should be the name of a folder of .rbxm(x) files in ./tests
local yourTest = testFolder(yourFunction: (fileContents: string, opts: types.opts) -> string | boolean, yourFunctionsOpt: types.opts, folderName: string)
for fileName, result in pairs(yourTest) do
if result then
print(`Test failed: {fileName} yourReason`)
process.exit(1)
end
end
print("All tests passed for files in yourFolderName.")When you add a new option (via a command line flag), add it to ./lib/types.luau, following the existing conventions.
When you add a new function to any library, add it to the function's type. If you add a new library, define a type for it and type cast the module to it:
export type YourModule = {
yourFunction: (...) -> unknown,
}
-- note the camel case vs pascal case
local yourModule = {} :: YourModuleCopyright (C) 2025 Filoxen Labs
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.