Module configuration organisation

Recently I came to the problem with editing configurations of a ModuleScript.

For example, I want to toggle if headtilt is on in the ModuleScript HeadTilt.

The original method I used is to have a centre controller module that stores all the configurations of different client modules.

local Controller = {}
local self = Controller

Controller.Configs = {
	HeadTiltEnabled = true,
}

Controller.EditConfig = function(Config,Value)
	assert(self.Configs[Config],"Config doesn't exist")
	assert(typeof(Value)==typeof(self.Configs[Config]),"Type doesn't match")
	self.Configs[Config] = Value
	--re-initializes the module that has config being edited--
	--in my code I uses separate tables to store configs so--
	--knowing which module to init is easy--
end

return Controller

For ease of reading I simplified the table structure, instead of using a single table I actually uses one for each module.

With this, in my modulescripts, I can simply do

local HeadTilt = {}
local self = HeadTilt
local Controller = require(game.ReplicatedStorage.Example.Controller)
HeadTilt.Init = function ()
	local HeadTiltEnabled = Controller.Configs.HeadTiltEnabled
	--unbinds function from renderstep--
	if HeadTiltEnabled then
		--binds headtilt function to renderstep--
	end
end

return HeadTilt

This method works totally fine but recently I saw someone’s modulescript using bindable events to do configurations, for example he parented a EditConfig BindableEvent under the modulescript, and in the modulescript there is

local EditConfig = script:WaitForChild("EditConfig")
EditConfig.Event:Connect(function(Config,Value)
	--asserting--
	self.Configs[Config] = value
end

I wonder which one would be better, in case of performace and organisation etc.?
What I think is using BindableEvents will save you debugging from requiring the controller module that may cause some glitches, but really is it? What are some advantages and disadvantages of using each method?

Any help on the topic will be appreciated!

tl;dr: They’re nearly the same, with the same functionality and Lua environment restrictions. My real advice here is that you shouldn’t be re-initializing your modules as

Your current setup using the controller module will adjust values based on the respective Lua Environment it was called on (i.e. Changing the values on a LocalScript will change the “Local version” of the module that is shared between all local scripts that require the module script, and same goes for the Server side)

The Bindable is dependent on the object being called and only works on the same side of the Client-Server boundary, thus it’s going to have the same effect and restrictions (Fire bindable from a local script adjusts the “Local Version” of the module and same from the server side)

In terms of usability, its also pretty evenly split:

  • require the controller to edit the values and call the function (~2 lines of code)
  • Declare the bindable and fire it (Also ~2 lines)

If you wanted to edit the Server Version from a Client environment then you’d need to implement Remotes, but I’m not sure if that’s what you’re after, may also pose security risks but idk how big the exploiting scene is nowadays.

Well that’s what I’m doing, just editing client modules such as headtilts and animations. So client-client is ok and simply what I want.
It’s just that is there a way to config the module in a more effiecient way, as you’ve said without init the module again. What can I do other than disconnecting the functions and then check if it’s on to do so?

I wouldn’t bother adjusting the method you use unless you have an active desire to use Bindables for some other additional reason.

Regarding the question: You, my friend, are a prime candidate to implement Metatables - Or more specifically the metamethods associated with them. Unfortunately there’s no .Changed equivalent for when a table value updates, but what you can do is call the table and then using the __call(table,…) metamethod, you can alter the table values as desired based on the arguments you pass.

Didn’t test this but I think it gets the idea across:

local Controller = {}
Controller.Configs = {
 HeadTiltEnabled = true,
}
local meta_table = {
 __call = function(table,args_Table)
 if args_Table.Instructions == "Change_Config" then
  Controller.Configs[args_Table.ConfigurationToChange] = args_Table.NewConfigurationValue
  end
 end
}

setmetatable(Controller.Configs,meta_table)
Controller.Configs({Instructions = "Change_Config"; ConfigurationToChange = "HeadTiltEnabled"; NewConfigurationValue = false})
1 Like

Will definetly try this out. Knew metatables for a long time but haven’t gone deep into it. It seems very useful! It’s like a case similar to ContextActionService I guess, making things a lot more simple and efficient!

There is a method not to init the modules again though, but that would require calling controller.config instead of using local config = controller.config at the start which I think will lag out things a bit.

Ah, realizing I’ve misinterpreted an earlier post about reinitializing- got too eager there, dont think the metatables are relevant

Zooming out in scope here, what is this module used for? From what I can gather its meant to be acting as a Character Settings type thing, and is being required by each client that joins? If so it might make more sense to have an Attribute on the ModuleScript itself and Connect a AttributeChanged event, and depending on the new value it either activates the head tilt or disables it. This would mean you only need to run the “Initialize” portion once, and then because you have a .Changed listener, you can let that act as a toggle rather than running the initialize function, checking a value, unbinding from RS, and then Rebinding to RS

Regarding the table method, I can’t think of a great solution to determine when a value changes without running a constant loop which isn’t ideal

Don’t have full context of the module though

1 Like

Literally forgot about custom attributes! Now it’s all simple. Thanks for clearing things up

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.