4. SuperbulletFrameworkV1-Knit
a. Dynamic Remotes

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 FunctionRoblox EquivalentPurpose
RegisterClientSignalRemoteEventFire events between server and client
RegisterClientMethodRemoteFunctionRequest data from server and get a response
RegisterClientPropertyRemoteEvent + state syncReplicate 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?): RemoteSignal

Parameters:

  • service - The service to register on
  • signalName - The name of the signal
  • unreliable - (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): MethodWrapper

Parameters:

  • service - The service to register on
  • methodName - 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)
end

RegisterClientProperty

Registers a new RemoteProperty on the service's Client table.

Knit.RegisterClientProperty(service: Service, propertyName: string, initialValue: any): RemoteProperty

Parameters:

  • service - The service to register on
  • propertyName - The name of the property
  • initialValue - 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() runs

Attempting 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 InventoryService

Component (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 ItemHandler

Error 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()