Summary
A services manager for the CitizenFX platform. It keeps track of various providers, all registered for a specific service. Scripts can retrieve a registered provider, which implement a specific interface, and use it without knowing anything about the implementation of the provider itself.
Why r3_servicesmanager?
If you’ve ever wanted to make a resource for FiveM and published it, you probably got the question to support <insert any framework here>. And if you’ve ever made a server and installed a lot of resources on it, you probably ran into “bridge”-like resources which handled the compatibility with frameworks.
r3_servicesmanager provides a solution for this. It gives developers a way to support many different frameworks (and other scripts) without having to program support for each one. Resources can simply register themselves and, as long as they implement the defined interfaces, will be compatible with every script utilising r3_servicesmanager for its dependencies.
Some features of the services manager:
- You no longer need to create many if statements for every framework you want to be compatible with, just retrieve the provider and call the method you need.
- No need to figure out which provider you need. The services manager always gives you the registered provider with the highest priority for which the required resource is started.
- Any resource can make itself compatible, no need to update your script to add support. This also means that you don’t need to update your resource when <insert any resource> has an update, the provider simply needs to be updated and it will be compatible again!
- Server owners can choose what to use! Since the providers are returned based on a priority, you can increase the priority of your preferred <framework, progressbar, etc.> and it will be used in every script utilising this. And you can also swap out resources (as long as they are compatible with this), for example if you want to switch the style of notifications in your server you can remove the old notification script and put in a new one which will then be used instead.
- Runs at 0.00 ms.
What is supported?
Pretty much anything can register itself under a service key, but to keep things clear I’ve defined some interfaces for common services (notifications, jobs, frameworks, etc.). These can all be found at the services documentation page. Type definitions in Lua and TypeScript can be found in the repository. If you need an API for a service that is not defined, feel free to ask for it here or create an issue on github! I’ll check if I can define it if it’s commonly used.
There are some providers included with this resource for popular resources such as ESX, QBOX and ox_lib. These can be found in the providers folder of the repository. If you need any other providers you are welcome to ask for them here or create an issue as well.
You can also define your own “service”, and use it across your own resources. Just register it under a non-taken service key, preferably something that will never be taken i.e. including your username, and you can retrieve it in your resources.
Usage
Registering a service provider
You can register a service provider using the register export:
exports.r3_servicesmanager:register(service, provider, priority, resource)
This will register your provider for the given service with a given priority.
Parameters:
- service:
stringThe service to register. - provider:
tableA table of functions implementing the defined interface for the service. - priority:
ServicePriorityThe priority of the provider, it is recommended to use priority2and make it configurable for server owners. - resource:
stringThe resource this provider provides the service for. The provider will be unregistered automatically if this resource stops. Usually you should putGetCurrentResourceName()here.
Returns:
nil
Loading a service provider
You can retrieve a service provider using the load export:
local serviceProvider = exports.r3_servicesmanager:load(service)
This loads the provider directly if one is registered.
Parameters:
- service:
stringThe service to load the provider for.
Returns:
tableThe currently registered provider for the service with the highest priority.nilIf there is no provider registered for the service.
Retrieving a registration
If you need more information about a provider, you can retrieve the RegisteredProvider completely using the getRegistration export:
local registeredProvider = exports.r3_servicesmanager:getRegistration(service)
This way you can check which provider is currently active, and check for which resource it is and what priority it has for instance.
Parameters:
- service:
stringThe service to get the registration for.
Returns:
RegisteredProviderThe full registration of the currently registered provider for the service with the highest priority.nilIf there is no provider registered for the service.
Retrieving all registrations for a service
You can also retrieve all registrations for a specific service using the getRegistrationsForService export:
local registeredProviders = exports.r3_servicesmanager:getRegistrationsForService(service)
Parameters:
- service:
stringThe service to get the registrations for.
Returns:
RegisteredProvider[]A list of registered providers for the service.
Retrieving all registrations for a resource
You can also retrieve all registrations for a specific resource using the getRegistrationsForResource export:
local registeredProviders = exports.r3_servicesmanager:getRegistrationsForResource(resource)
Parameters:
- resource:
stringThe resource to get the registrations for.
Returns:
RegisteredProvider[]A list of registered providers for the resource.
Getting all known services
To retrieve all known services you can use the getKnownServices export:
local knownServices = exports.r3_servicesmanager:getKnownServices()
Returns:
string[]A list of services that are known by the services manager, meaning they have a provider registered currently or had at least one before.
Checking if there is a provider for a service
To check if there is currently a provider registered for a service you can use the isProvidedFor export:
exports.r3_servicesmanager:isProvidedFor(service)
Parameters:
- service:
stringThe service to check if there is a provider registered for it.
Events
Events are triggered when a provider gets registered or unregistered. The following events get triggered:
r3_servicesmanager:providerRegisteredr3_servicesmanager:providerUnregistered
Both events provide the RegisteredProvider in question as an argument.
Types
The following types are used with the provided exports:
ServicePriority
The priority of a service provider.
Fields:
- Lowest: 0
- Low: 1
- Normal: 2
- High: 3
- Highest: 4
RegisteredProvider
A registration of a provider for a service.
Methods:
- getService():
stringThe service the provider provides. - getProvider():
tableThe provider object. - getPriority():
ServicePriorityThe priority of the provider. - getResource():
stringThe resource the provider was registered for. - getInvokingResource():
stringThe resource that registered the provider.
Currently defined services
This is a quick overview of the methods available for each service. For full details on each service please visit the corresponding documentation here. Providers for each service have been included for popular open-source resources, currently these include resources from esx, qb-core, qbox and overextended. More providers are planned (suggestions on which to do first are welcome!). This resource should also be compatible with RedM, so I will be making some providers for that soon too.
Banking
The banking providers provide a service that allows resources to interact with bank accounts.
Server
local bankingProvider = exports.r3_servicesmanager:load("banking")
bankingProvider.getAccountBalance(account)
bankingProvider.addAccountBalance(account, amount)
bankingProvider.removeAccountBalance(account, amount)
bankingProvider.accountHasBalance(account, amount)
Callback
The callback providers provide a service that allows resources to register and trigger callbacks.
Callback service documentation
Client
local callbackProvider = exports.r3_servicesmanager:load("callback")
callbackProvider.triggerServerCallback(name, cb, ...)
local result = callbackProvider.awaitServerCallback(name, ...)
Server
local callbackProvider = exports.r3_servicesmanager:load("callback")
callbackProvider.registerServerCallback(name, cb)
Context menu
The context menu providers provide a service that allows resources to show players a context menu.
Context menu service documentation
Client
local contextMenuProvider = exports.r3_servicesmanager:load("contextMenu")
contextMenuProvider.openMenu(contextMenuOptions)
contextMenuProvider.closeMenu()
Economy
The economy providers provide a service that allows resources to interact with the economy, specifically players their money.
Server
local economyProvider = exports.r3_servicesmanager:load("economy")
economyProvider.getPlayerBalance(playerId, account)
economyProvider.setPlayerBalance(playerId, account, amount)
economyProvider.addPlayerBalance(playerId, account, amount)
economyProvider.removePlayerBalance(playerId, account, amount)
economyProvider.playerHasBalance(playerId, account, amount)
Employment
The employment providers provide a service that allows resources to interact with players their jobs.
Employment service documentation
Client
local employmentProvider = exports.r3_servicesmanager:load("employment")
employmentProvider.getPlayerJob()
employmentProvider.playerHasJob(jobName, jobGrade)
employmentProvider.onPlayerJobChanged(callback)
Server
local employmentProvider = exports.r3_servicesmanager:load("employment")
employmentProvider.getJob(jobName)
employmentProvider.jobExists(jobName, jobGrade)
employmentProvider.getOnlineJobCount(jobName)
employmentProvider.getPlayerJob(playerId)
employmentProvider.setPlayerJob(playerId, jobName, jobGrade)
employmentProvider.playerHasJob(playerId, jobName, jobGrade)
Identity
The identity providers provide a service that allows resources to retrieve identifying information of a player.
Identity service documentation
Server
local identityProvider = exports.r3_servicesmanager:load("identity")
identityProvider.getPlayerIdentifier(playerId)
identityProvider.getPlayerName(playerId)
Inventory
The inventory providers provide a service that allows resources to interact with the inventory of players.
Inventory service documentation
Server
local inventoryProvider = exports.r3_servicesmanager:load("inventory")
inventoryProvider.addItem(playerId, itemName, amount)
inventoryProvider.removeItem(playerId, itemName, amount)
inventoryProvider.getItemCount(playerId, itemName)
inventoryProvider.hasItem(playerId, itemName, amount)
Metadata
The metadata providers provide a service that allows resources to store metadata specific to a player.
Metadata service documentation
Server
local metadataProvider = exports.r3_servicesmanager:load("metadata")
metadataProvider.getPlayerMetadata(playerId, key)
playerDataProvider.setPlayerMetadata(playerId, key, value)
Notification
The notification providers provide a service that allows resources to send notifications to players.
Notification service documentation
Client
local notificationProvider = exports.r3_servicesmanager:load("notification")
notificationProvider.showNotification(message, notificationOptions)
Server
local notificationProvider = exports.r3_servicesmanager:load("notification")
notificationProvider.showNotification(playerId, message, notificationOptions)
Player state
The player state providers provide a service that allows resources to check whether players are fully loaded.
Player state service documentation
Client
local playerStateProvider = exports.r3_servicesmanager:load("playerState")
playerStateProvider.isPlayerLoaded()
playerStateProvider.onPlayerLoaded(callback)
Progress
The progress providers provide a service that allows resources to show a progress bar to players.
Progress service documentation
Client
local progressProvider = exports.r3_servicesmanager:load("progress")
progressProvider.startProgress(label, duration, progressOptions)
progressProvider.cancelProgress()
Stash
The stash providers provide a service that allows resources to interact with the inventory of objects (i.e. stashes, vehicles).
Server
local stashProvider = exports.r3_servicesmanager:load("stash")
stashProvider.addItem(inventoryRef, itemName, amount)
stashProvider.removeItem(inventoryRef, itemName, amount)
stashProvider.getItemCount(inventoryRef, itemName)
stashProvider.hasItem(inventoryRef, itemName, amount)
Target
The target providers provide a service that allows resources to create targetable interactions.
Client
local targetProvider = exports.r3_servicesmanager:load("target")
targetProvider.enableTargeting(bool)
targetProvider.addGlobalObject(options)
targetProvider.removeGlobalObject(optionNames)
targetProvider.addGlobalPlayer(options)
targetProvider.removeGlobalPlayer(optionNames)
targetProvider.addGlobalVehicle(options)
targetProvider.removeGlobalVehicle(optionNames)
targetProvider.addModel(models, options)
targetProvider.removeModel(models, optionNames)
targetProvider.addEntity(netIds, options)
targetProvider.removeEntity(netIds, optionNames)
targetProvider.addLocalEntity(entities, options)
targetProvider.removeLocalEntity(entities, optionNames)
targetProvider.addSphereZone(parameters)
targetProvider.addBoxZone(parameters)
targetProvider.addPolyZone(parameters)
targetProvider.removeZone(name)
Text UI
The text UI providers provide a service that allows resources to show a text UI to players.
Client
local textUIProvider = exports.r3_servicesmanager:load("textUI")
textUIProvider.showTextUI(text)
textUIProvider.hideTextUI()
Usable items
The usable items providers provide a service that allows resources to register usable items.
Usable items service documentation
Server
local usableItemsProvider = exports.r3_servicesmanager:load("usableItems")
usableItemsProvider.registerUsableItem(itemName, cb)
