Dynamic Remotes
This system lets you create RemoteEvents and RemoteFunctions automatically from your component modules. Part of SuperbulletFrameworkV1-Knit (2025).
What Are These?
If you're familiar with Roblox networking:
| Knit Function | Roblox Equivalent | Purpose |
|---|---|---|
RegisterClientSignal | RemoteEvent | Fire events between server and client |
RegisterClientMethod | RemoteFunction | Request data from server and get a response |
RegisterClientProperty | RemoteEvent + state sync | Replicate a value to all clients automatically |
These functions automate the creation of Roblox's networking instances. Instead of manually creating RemoteEvents/RemoteFunctions in ReplicatedStorage and writing boilerplate connection code, you call one function and it's done.
Why Use This?
For AI-assisted development: This structured approach helps SuperbulletAI understand your networking code better. When remotes are registered with clear names in predictable locations, AI can:
- Easily find and modify server-client communication
- Generate consistent networking code
- Understand the relationship between components and their remotes
For code organization: Instead of defining all remotes in one giant service file, each component can register its own remotes. Related code stays together.
Available Functions
RegisterClientSignal
Registers a new RemoteSignal on the service's Client table.
Knit.RegisterClientSignal(service: Service, signalName: string, unreliable: boolean?): RemoteSignalParameters:
service- The service to register onsignalName- The name of the signalunreliable- (Optional) Use UnreliableRemoteEvent (default: false)
Returns: The RemoteSignal, so you can immediately chain :Connect()
Example:
-- In a component's Init() function:
local QuestService = Knit.GetService("QuestService")
Knit.RegisterClientSignal(QuestService, "OnQuestComplete"):Connect(function(player, questId)
print(player.Name, "completed quest", questId)
end)RegisterClientMethod
Registers a new RemoteFunction on the service's Client table.
Knit.RegisterClientMethod(service: Service, methodName: string): MethodWrapperParameters:
service- The service to register onmethodName- The name of the method
Returns: A MethodWrapper with .OnServerInvoke property (Roblox-style)
Example:
-- In a component's Init() function:
local QuestService = Knit.GetService("QuestService")
Knit.RegisterClientMethod(QuestService, "GetActiveQuests").OnServerInvoke = function(self, player)
return QuestManager:GetPlayerQuests(player)
endRegisterClientProperty
Registers a new RemoteProperty on the service's Client table.
Knit.RegisterClientProperty(service: Service, propertyName: string, initialValue: any): RemotePropertyParameters:
service- The service to register onpropertyName- The name of the propertyinitialValue- The initial value for the property
Returns: The RemoteProperty, so you can use :Set() / :Get()
Example:
-- In a component's Init() function:
local GameService = Knit.GetService("GameService")
local configProp = Knit.RegisterClientProperty(GameService, "GameConfig", {
MaxPlayers = 10,
RoundTime = 300,
})
-- Later, you can update it:
configProp:Set({ MaxPlayers = 20, RoundTime = 600 })Timing Requirements
All RegisterClient* functions must be called before Knit.Start() completes. The recommended place is inside a component's Init() function:
Lifecycle Order:
1. Knit.CreateService() called
2. Knit.Start() begins
3. Service KnitInit() runs
4. Component Init() runs <-- Register here!
5. ClientExtension locks (no more registrations allowed)
6. Service KnitStart() runs
7. Component Start() runsAttempting to register after the Init phase will throw an error.
Complete Example
Service (init.lua):
local Knit = require(ReplicatedStorage.Packages.Knit)
local InventoryService = Knit.CreateService({
Name = "InventoryService",
Client = {},
Instance = script, -- Enables automatic component initialization
})
function InventoryService:KnitStart()
-- Main service logic
end
function InventoryService:KnitInit()
-- Get service references
end
return InventoryServiceComponent (Components/Others/ItemHandler.lua):
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Knit = require(ReplicatedStorage.Packages.Knit)
local ItemHandler = {}
function ItemHandler.Init()
local InventoryService = Knit.GetService("InventoryService")
-- Register a signal for item collection
Knit.RegisterClientSignal(InventoryService, "OnItemCollected"):Connect(function(player, itemId)
print(player.Name, "collected item:", itemId)
end)
-- Register a method to get inventory
Knit.RegisterClientMethod(InventoryService, "GetInventory").OnServerInvoke = function(self, player)
return ItemHandler:GetPlayerInventory(player)
end
end
function ItemHandler.Start()
-- Component runtime logic
end
function ItemHandler:GetPlayerInventory(player)
-- Return inventory data
return {}
end
return ItemHandlerError Prevention
The system includes several safeguards:
- Duplicate prevention: Cannot register the same name twice on a Client table
- Timing validation: Cannot register after the Init phase
- Service validation: Must pass a valid service created with
Knit.CreateService() - Name validation: Signal/method/property names must be non-empty strings
Client-Side Access
Once registered, clients can access these items just like any other Knit remote:
-- Client-side
local InventoryService = Knit.GetService("InventoryService")
-- Use the dynamically registered signal
InventoryService.OnItemCollected:Connect(function(itemId)
print("I collected:", itemId)
end)
-- Use the dynamically registered method
local inventory = InventoryService:GetInventory()