Skip to main content

Roam

Roam follows a design pattern similar to Knit, but is more lightweight (Shoutout to Stephen Leitnick [Sleitnick]). It removes all networking and replication functionality, and instead focuses on providing a simple method to easily initialize Services given to it and provide global accessors.

Roam gathers a collection of specified services and initializes 'syncronously'. Once all services have been fully initialized, it then starts them 'asyncronously' by spawning their 'RoamStart' method in a new thread.

Roam enforces contracts to ensure that only the Services that you intend are initialized. By following the contracts of service construction/registration, Roam is able to ensure that nothing that isnt intended to be initialized doesnt cause any issues during the loading or start process.

[CONTRACTS]

  • Services must be created/registered before Roam is started.
  • Services must be created/registered with a unique name.
  • Services with RoamInit and RoamStart methods will have those methods called when Roam is started at the appropriate time. (Names are configurable)
  • All Services are guaranteed safe to access in RoamStart.
  • Only StaticMethods are safe to call prior to RoamStart.

[EXAMPLE USAGE]

local Roam = require(ReplicatedStorage.Roam)

-- Just iterates through all the children of the given parents
-- and requires any module scripts that match the given predicate
Roam.requireModules({
	ReplicatedStorage.Shared;
	ServerScriptService.Server;
})

-- Start Roam
Roam.start()
:andThenCall(print, "Roam started!")
:catch(warn)

-- Accessing a potential Service
Roam.getService("MyService"):DoSomething()

Types

ServiceConfig

interface ServiceConfig {
Namestring--

Name of the Service. Must be unique. Used when accessing via .getService

RequiredServices{Service}?--

The Services that this Service depends on. Roam will ensure that these Services are initialized before this Service.

StartMethodNamestring?--

Overrides default StartMethodName of "RoamStart"

InitMethodNamestring?--

Overrides default InitMethodName of "RoamInit"

}
local myOtherService = require(ReplicatedStorage.MyOtherService)

local MyService = Roam.createService {
	Name = "MyService",
	RequiredServices = {myOtherService},
}
Automatic Service Dependency Resolution (RequiredServices)

If you require services to a global variable then ROAM will automatically add the service to the RequiredServices table. This will NOT work if it is required to a local variable. If it is localized then you must manually add it to the RequiredServices table if you want it marked as a dependency.

myOtherService = require(ReplicatedStorage.MyOtherService) -- services required to global variables are automatically added to RequiredServices

local MyService = Roam.createService { Name = "MyService" }
Deffering RequiredServices

Do NOT add services to the RequiredServices after you have created or registered the service. This will cause undefined behavior.

Properties

ClassName

Roam.ClassName: "Roam"

The ClassName of the Roam module.

Debug

Roam.Debug: boolean

Whether or not to print debug messages. Default is false.

Bootstrappers

Roam.Bootstrappers: {
Server(scriptScript) → (),
Client(scriptScript) → ()
}

A table of generic bootstrappers for Roam / Orion.

Functions

createService

Roam.createService(serviceDefServiceConfig) → Service

Creates a Service/Table with Roam to be Initialized and Started when Roam starts. Cannot be called after Roam has been started. This is the advised method of creating services over registering them.

local Roam = require(ReplicatedStorage.Roam)

local MyService = Roam.createService { Name = "MyService" }

function MyService:DoSomething()
	print("yeee haw!")
end

-- Default StartMethodName is "RoamStart" (Can be overriden in service creation config)
function MyService:RoamStart()
	print("MyService started!")
	self:DoSomething()
end

-- Default InitMethodName is "RoamInit" (Can be overriden in service creation config)
function MyService:RoamInit()
	print("MyService initialized!")
end

return MyService

registerService

Roam.registerService(
serviceService,
serviceConfig(ServiceConfig | string)?
) → Service

Registers a Service/Table with Roam to be Initialized and Started when Roam starts. Cannot be called after Roam has been started. This method was added to allow for easy backporting of existing services to Roam.

local MyRegisteredService = {}

function MyRegisteredService:Start()
	print("MyRegisteredService started!")
end

function MyRegisteredService:Init()
	print("MyRegisteredService initialized!")
end

local Roam = require(ReplicatedStorage.Roam)
Roam.registerService(MyRegisteredService, {
	Name = "MyRegisteredService";
	StartMethodName = "Start"; -- Overrides default StartMethodName of "RoamStart" [Optional]
	InitMethodName = "Init"; -- Overrides default InitMethodName of "RoamInit" [Optional]
})

return MyRegisteredService

requireModules

Roam.requireModules(
parentsInstance | {Instance},
config{
DeepSearchboolean?,
RequirePredicate((objModuleScript) → boolean)?,
IgnoreDescendantsPredicate((objInstance) → boolean)?,
}?
) → {Service}

Requires all the modules that are children of the given parent. This is an easy way to quickly load all services that might be in a folder. Takes an optional predicate function to filter which modules are loaded. Services collected this way must not yield.

  • DeepSearch -> whether it checks descendants or just children
  • RequirePredicate -> a predicate function that determines whether a module should be required
  • IgnoreDescendantsPredicate -> A Predicate for whether the Descendants of the Module should be Searched (Only matters if DeepSearch is true)
local pred = function(obj: ModuleScript): boolean
	return obj.Name:match("Service$") ~= nil
end

Roam.requireModules(ReplicatedStorage.Shared, {
	DeepSearch = true,
	RequirePredicate = pred,
	IgnoreDescendantsPredicate = function(obj: Instance): boolean
		return obj.Name == "Ignore"
	end,
})

getNameFromService

Roam.getNameFromService(serviceService) → string

Fetches the name of a registered Service.

getService

Roam.getService(serviceNamestring) → Service

Fetches a registered Service by name. Cannot be called until Roam has been started.

start

Roam.start(postInitPreStart(() → (Promise?))?) → Promise

Starts Roam. Should only be called once. Optional argument postInitPreStart is a function that is called after all services have been initialized, but before they are started.

caution

Be sure that all services have been created before calling Start. Services cannot be added later.

Roam.start()
:andThenCall(print, "Roam started!")
:catch(warn)

onStart

Roam.onStart() → Promise

Returns a promise that is resolved once Roam has started. This is useful for any code that needs to tie into Roam services but is not the script that called Start.

Roam.onStart():andThen(function()
	local MyService = Roam.Services.MyService
	MyService:DoSomething()
end):catch(warn)

isReady

Roam.isReady() → boolean

Returns whether or not Roam has been successfully started and is ready for external access.

Show raw api
{
    "functions": [
        {
            "name": "createService",
            "desc": "Creates a Service/Table with Roam to be Initialized and Started when Roam starts.\nCannot be called after Roam has been started. This is the advised method of creating\nservices over registering them.\n\n```lua\nlocal Roam = require(ReplicatedStorage.Roam)\n\nlocal MyService = Roam.createService { Name = \"MyService\" }\n\nfunction MyService:DoSomething()\n\tprint(\"yeee haw!\")\nend\n\n-- Default StartMethodName is \"RoamStart\" (Can be overriden in service creation config)\nfunction MyService:RoamStart()\n\tprint(\"MyService started!\")\n\tself:DoSomething()\nend\n\n-- Default InitMethodName is \"RoamInit\" (Can be overriden in service creation config)\nfunction MyService:RoamInit()\n\tprint(\"MyService initialized!\")\nend\n\nreturn MyService\n```",
            "params": [
                {
                    "name": "serviceDef",
                    "desc": "",
                    "lua_type": "ServiceConfig"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Service\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 246,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "registerService",
            "desc": "Registers a Service/Table with Roam to be Initialized and Started when Roam starts.\nCannot be called after Roam has been started. This method was added to allow for easy\nbackporting of existing services to Roam.\n\n```lua -- MyRegisteredService.lua\nlocal MyRegisteredService = {}\n\nfunction MyRegisteredService:Start()\n\tprint(\"MyRegisteredService started!\")\nend\n\nfunction MyRegisteredService:Init()\n\tprint(\"MyRegisteredService initialized!\")\nend\n\nlocal Roam = require(ReplicatedStorage.Roam)\nRoam.registerService(MyRegisteredService, {\n\tName = \"MyRegisteredService\";\n\tStartMethodName = \"Start\"; -- Overrides default StartMethodName of \"RoamStart\" [Optional]\n\tInitMethodName = \"Init\"; -- Overrides default InitMethodName of \"RoamInit\" [Optional]\n})\n\nreturn MyRegisteredService\n```",
            "params": [
                {
                    "name": "service",
                    "desc": "",
                    "lua_type": "Service"
                },
                {
                    "name": "serviceConfig",
                    "desc": "",
                    "lua_type": "(ServiceConfig | string)?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Service\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 295,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "requireModules",
            "desc": "Requires all the modules that are children of the given parent. This is an easy\nway to quickly load all services that might be in a folder. Takes an optional predicate\nfunction to filter which modules are loaded. Services collected this way must not yield.\n- `DeepSearch` -> whether it checks descendants or just children\n- `RequirePredicate` -> a predicate function that determines whether a module should be required\n- `IgnoreDescendantsPredicate` -> A Predicate for whether the Descendants of the Module should be Searched (Only matters if DeepSearch is true)\n\n```lua\nlocal pred = function(obj: ModuleScript): boolean\n\treturn obj.Name:match(\"Service$\") ~= nil\nend\n\nRoam.requireModules(ReplicatedStorage.Shared, {\n\tDeepSearch = true,\n\tRequirePredicate = pred,\n\tIgnoreDescendantsPredicate = function(obj: Instance): boolean\n\t\treturn obj.Name == \"Ignore\"\n\tend,\n})\n```",
            "params": [
                {
                    "name": "parents",
                    "desc": "",
                    "lua_type": "Instance | { Instance }"
                },
                {
                    "name": "config",
                    "desc": "",
                    "lua_type": "{\n\t\tDeepSearch: boolean?,\n\t\tRequirePredicate: ((obj: ModuleScript) -> boolean)?,\n\t\tIgnoreDescendantsPredicate: ((obj: Instance) -> boolean)?,\n\t}?\n"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{ Service }\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 348,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "getNameFromService",
            "desc": "Fetches the name of a registered Service.",
            "params": [
                {
                    "name": "service",
                    "desc": "",
                    "lua_type": "Service"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "string\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 400,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "getService",
            "desc": "Fetches a registered Service by name.\nCannot be called until Roam has been started.",
            "params": [
                {
                    "name": "serviceName",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Service\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 408,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "start",
            "desc": "Starts Roam. Should only be called once.\nOptional argument `postInitPreStart` is a function that is called\nafter all services have been initialized, but before they are started.\n\n:::caution\nBe sure that all services have been created _before_\ncalling `Start`. Services cannot be added later.\n:::\n\n```lua\nRoam.start()\n:andThenCall(print, \"Roam started!\")\n:catch(warn)\n```",
            "params": [
                {
                    "name": "postInitPreStart",
                    "desc": "",
                    "lua_type": "(() -> (Promise?))?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 433,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "onStart",
            "desc": "Returns a promise that is resolved once Roam has started. This is useful\nfor any code that needs to tie into Roam services but is not the script\nthat called `Start`.\n```lua\nRoam.onStart():andThen(function()\n\tlocal MyService = Roam.Services.MyService\n\tMyService:DoSomething()\nend):catch(warn)\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 572,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "isReady",
            "desc": "Returns whether or not Roam has been successfully started and is ready for external access.",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 583,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        }
    ],
    "properties": [
        {
            "name": "ClassName",
            "desc": "The ClassName of the Roam module.",
            "lua_type": "\"Roam\"",
            "source": {
                "line": 204,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "Debug",
            "desc": "Whether or not to print debug messages. Default is false.",
            "lua_type": "boolean",
            "source": {
                "line": 210,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        },
        {
            "name": "Bootstrappers",
            "desc": "A table of generic bootstrappers for Roam / Orion.",
            "lua_type": "{Server: (script: Script) -> (), Client: (script: Script) -> ()}",
            "source": {
                "line": 216,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        }
    ],
    "types": [
        {
            "name": "ServiceConfig",
            "desc": "```lua\nlocal myOtherService = require(ReplicatedStorage.MyOtherService)\n\nlocal MyService = Roam.createService {\n\tName = \"MyService\",\n\tRequiredServices = {myOtherService},\n}\n```\n:::tip Automatic Service Dependency Resolution (RequiredServices)\nIf you require services to a `global` variable then ROAM will automatically add the service to the RequiredServices table.\nThis will ***NOT*** work if it is required to a `local` variable. If it is localized then you must manually add it to the RequiredServices table\nif you want it marked as a dependency.\n```lua\nmyOtherService = require(ReplicatedStorage.MyOtherService) -- services required to global variables are automatically added to RequiredServices\n\nlocal MyService = Roam.createService { Name = \"MyService\" }\n```\n:::\n\n:::caution Deffering RequiredServices\nDo NOT add services to the RequiredServices after you have created or registered the service. This will cause undefined behavior.\n:::",
            "fields": [
                {
                    "name": "Name",
                    "lua_type": "string",
                    "desc": "Name of the Service. Must be unique. Used when accessing via .getService"
                },
                {
                    "name": "RequiredServices",
                    "lua_type": "{Service}?",
                    "desc": "The Services that this Service depends on. Roam will ensure that these Services are initialized before this Service."
                },
                {
                    "name": "StartMethodName",
                    "lua_type": "string?",
                    "desc": "Overrides default StartMethodName of \"RoamStart\""
                },
                {
                    "name": "InitMethodName",
                    "lua_type": "string?",
                    "desc": "Overrides default InitMethodName of \"RoamInit\""
                }
            ],
            "source": {
                "line": 124,
                "path": "src/roam/src/Shared/Roam/init.lua"
            }
        }
    ],
    "name": "Roam",
    "desc": "Roam follows a design pattern similar to Knit, but is more lightweight (Shoutout\nto Stephen Leitnick [Sleitnick]). It removes all networking and replication\nfunctionality, and instead focuses on providing a simple method to easily\ninitialize Services given to it and provide global accessors.\n\nRoam gathers a collection of specified services and initializes 'syncronously'.\nOnce all services have been fully initialized, it then starts them 'asyncronously' by\nspawning their 'RoamStart' method in a new thread.\n\nRoam enforces contracts to ensure that only the Services that you intend are\ninitialized. By following the contracts of service construction/registration,\nRoam is able to ensure that nothing that isnt intended to be initialized doesnt\ncause any issues during the loading or start process.\n\n[CONTRACTS]\n- Services must be created/registered before Roam is started.\n- Services must be created/registered with a unique name.\n- Services with `RoamInit` and `RoamStart` methods will have those methods\n  called when Roam is started at the appropriate time. (Names are configurable)\n- All Services are guaranteed safe to access in RoamStart.\n- Only StaticMethods are safe to call prior to RoamStart.\n\n[EXAMPLE USAGE]\n```lua -- init.Server.lua\nlocal Roam = require(ReplicatedStorage.Roam)\n\n-- Just iterates through all the children of the given parents\n-- and requires any module scripts that match the given predicate\nRoam.requireModules({\n\tReplicatedStorage.Shared;\n\tServerScriptService.Server;\n})\n\n-- Start Roam\nRoam.start()\n:andThenCall(print, \"Roam started!\")\n:catch(warn)\n\n-- Accessing a potential Service\nRoam.getService(\"MyService\"):DoSomething()\n```",
    "source": {
        "line": 49,
        "path": "src/roam/src/Shared/Roam/init.lua"
    }
}