Is making a Module for Systems and suchlike 100% necessary?

I’ve had this thought for a while now; so for example: I have this Server Script that inserts a Folder in the Player, which also inserts all kinds of Values in said Folder. What it is for and what it does is not relevant, but if you must know; to put it simple, it’s like session data, kind of like leaderstats in a way.

Anyway, I like the idea of making systems such as this (among others obviously) into a Module, so when you need to add a new Value or say a new Folder for instance all you would have to do is in another Server Script elsewhere (referring to said Module) .newValue()/.newFolder() or something.

But my point is… Is that really necessary? Since we technically already have this kind of system; the “Instance” Global; so, create said Value or a Folder, set it’s Properties, done, right? – So this whole system could just be done inside a Server Script anyway with the associated RemoteEvents to get and set Values, right? Because the way I see it is, converting this whole system into a Module would just be like making another Instance Global, you see what I mean, no?

However, as I said; I have these functions that get and set a Value in the Sever Script that can be called via a RemoteEvent, or a BindableRemoteEvent if done on the Server. But in a Module, all I would have to do is require it, and call :get(aValue)/:set(aValue), right?

But of course, there are quite a few security flaws… With both; with the Server Script way: Any Exploiter could just Fire the RemoteEvent to the Server and set a Value… No good. With the Module way: The client would still have to Fire a RemoteEvent to set a Value, since setting it on the client is no good for the Server, plus I don’t think you can use a Module for both sides and nor would I want to.

I may sound silly with this, but it’s just a thought I had for a while, and haven’t really thought it through, so, some insight would be very helpful! :slight_smile:

I hope this explains it well, I would really appreciate some feedback. Any questions, please don’t hesitate to let me know! :slight_smile:

4 Likes

yes it is. integrate modules into all of your work. it follows the DRY principle and allows you to not have to rewrite code and functions. My latest plugin has about 20 modulescripts and the main PluginScript is roughly 50 lines of code thanks to this.

5 Likes

I don’t fully understand. Are you saying that you want to store the session data of each player internally as a dictionary (ie: local data = {[Player_1_UserID] = {Coins = 123, Gems = 5, Cars = {"Honda", "Toyota"}}, [Player_2_UserID] = SomeTable, etc...}) rather than storing it inside a “leaderstats” folder inside of the player object? I look at modulescripts as a way to make “global” functions. If I have some sort of algorithm that needs to be run multiple times in various different scripts and such, instead of writing that algorithm over and over again, in each script that I want to use it in, I just write it once inside of a modulescript, and then call the method from that modulescript instead of copying and pasting that code over and over and over again, for each time that I want to use it.

This is not for nothing. There is an advantage to this. The code will look cleaner, and the code won’t have as many lines of code. Plus, if a bug is found, or a modification has to be made to some of this “special” code, all that would need to be done is to make some modifications to the code inside of the appropriate modulescript instead of having to look through each script that uses this code, and make these modifications to each script.

But if you want to use modulescript for something, and you don’t get any type of “advantage” from doing it (read the above paragraph for an example of this “advantage”), then you don’t really have any reason to use a modulescript for whatever it is that you wanted to use it for in the first place.

Edit: So, to answer the question that I think you are asking, no; Modulescripts are not 100% necessary for “Systems”.

1 Like

The security flaws don’t really have anything to do with your structure, you just shouldn’t be trusting the client to set any values. It should all be handled by the server. By the way, how often do you use modules in general, I’m curious

1 Like

I see, thank you so much for your feedback, I really appreciate it! I only asked because turning the smallest of systems into a Module seems a bit redundant and a waste of extra needed time to make them a module; considering they are only small. But, I suppose turning them into a Module removes the possibility of difficulty and struggle when upgrading small systems to bigger! Thanks for this! :slight_smile:

1 Like

Haha no, that’s not what I meant at all, sorry if it’s confusing, I’m honestly not that great at explaining things.

The session data is an example of many small systems; and asking if it’s necessary to rather than code them in a regular Server Script, or code them in a Module instead. This small system, for example, contains 2 functions: one for getting a Vaue, and one for setting a Value. These said functions get called via RemoteEvent, or Bindable if requested from another Server Script elsewhere; I think’s that’s a bit messy, but in saying that, I don’t see a difference from doing it that way, and just requiring a Module and calling the function.


Quite, but I’m not saying “copy and paste the small system in another script”, what I’m saying is, what is the difference/benefits/cons in say; calling these methods in a Module, and just firing a Remote/Bindable to call these functions/methods, you see what I mean?

I suppose on the Server there wouldn’t be any difference, but on the client, there would be; as I said, I don’t think you can use a Module for both sides, plus that could be very bad for security, so you would still have to fire a RemoteEvent from the client to the Server THEN to the Module, just set a or get a Value, where as doing it the Server Script way, all you would have to do is on the client fire a RemoteEvent to the Server, and done, but as I said again, that can also be exploitable, so I’m in a bit of a pickle here.


This also falls into what the one I quoted you prior to this one.


This also falls into what the one I quoted you prior to this one.


Could you elaborate on this, please?


Thank you for your detailed feedback, I would like to hear back from you soon if possible! :slight_smile:

1 Like

Well, the thing is, the Client does indeed need to set some Values that only the client can detect. For instance, I have this Value, which tells where the player currently is in the game, like what place they are at (for example: cafe, shop, home, etc). Since this “where the player is” detection HAS to be done on the Client, the only way to set that Value is to, from the Client request the Server to do it. It’s not safe I know, but I really don’t see any other way unfortunately.


May I ask why?

I’ve been scripting for around 3-4 years and my organization on games was pretty bad and I didn’t catred much until i had to add features…Now I try to split everything as much as i can so it’s way more readable for others scripters and easier to work with and it will just save you lot of time. And you will have probably more performance doing this because you won’t have redundant functions.

edit: person I replied to deleted their comment smh
I don’t know why OP quickly discarded your answer although it doesn’t directly answer his question it’s still solid advice as getting sidetracked with things like this slows development down IMO.

1 Like

How I see it is that with ModuleScripts you can do literally anything. If you use Value Objects (or even attributes), you are limited to what the Value Object can store (and have to either abstract or write multiple times code to get the values), while module scripts can store anything, and even do more than just storing stuff. If you replace your values with a module script (that you could clone into the Player, or just have in ReplicatedStorage), then you can easily get rid of your BindableEvents and BindableFunctions with function calls from the module script. I dislike bindables (and remotes) because of the lack of autocomplete and type checking


Hold my bear

--

local RemoteFunction = script.RemoteFunction
local RemoteEvent = script.RemoteEvent

local RemoteProcedures = { -- For functions that do not return anything
	"SelectTeam",
	"SetReplicationFocus",
	-- "Stun",
}

local RemoteFunctions = { -- For functions that return stuff and/or yield
	"LoadCharacter",
}

if RunService:IsServer() then 
	RemoteEvent.OnServerEvent:Connect(function(Player : Player, Index, ...)
		if not table.find(RemoteProcedures, Index) and not table.find(RemoteFunctions, Index) then error("Player "..Player.UserId.." is trying to access restricted methods "..Index) end -- TODO -- Report user as exploiter
		PlayerModule[Index](PlayerModule, Player, ...)
	end)
	
	RemoteFunction.OnServerInvoke = function(Player : Player, Index, ...) 
		if not table.find(RemoteProcedures, Index) and not table.find(RemoteFunctions, Index) then error("Player "..Player.UserId.." is trying to access restricted methods "..Index) end -- TODO -- Report user as exploiter
		return PlayerModule[Index](PlayerModule, Player, ...)
	end
end

if RunService:IsClient() then
	for i, v in pairs(PlayerModule) do
		
		if table.find(RemoteProcedures, i) then 
			PlayerModule[i] = function(self, Player, ...)
				RemoteEvent:FireServer(i, ...)
			end
		end

		if table.find(RemoteFunctions, i) then 
			PlayerModule[i] = function(self, Player, ...)
				return RemoteFunction:InvokeServer(i, ...)
			end
		end
		-- else, do not change
	end
end

return PlayerModule

The strings inside the two tables are names of functions. These functions wont run on the client when called by it, but rather will be ran on the server. For example:

function PlayerModule:SelectTeam(Player : Player, TeamName : TeamsType) 
	-- ...
	-- This function doesn't return any value
end

The idea is to overwrite the function on the client with a new function that instead sends a remote event or remote function (and returns the value in the later case), to run the function on the server. This isn’t less secure than using RemoteEvents and RemoteFunctions as usual, but you have to be more careful, and put your sanity checks in the functions directly

I’ve purposefully made it so functions have to be added to a whitelist rather than a blacklist, so when you inevitably forget to add it to the list, it simply wont work rather than causing a vulnerability

I’ve tried doing this with some modules, and so far, I like it. It abstracts all the annoying RemoteEvent/Function logic with simple function calls and maintains auto complete and type checking (my biggest annoyance with remotes)
Something else I dislike with remotes is that they kinda hide the link between the client and server (you have to find which scripts fires and listens to whatever remote), while with this, that isn’t an issue

1 Like

I’m not quite sure where you’re going with this statement. doing it either way doesn’t have redundant functions. Unless you, for some reason, decide to code them for whatever reason. Could you elaborate, please?

I’m sorry, I’m afraid I do not know what you are talking about. Would you care to elaborate further? That would be really helpful, thank you! :slight_smile:

<call one function
<execute one line of code
<call another function
<repeat 99999 times
<return the original function call

i’m not necessarily saying this applies to your plugin, but for anyone editing your code it’s gonna be way easier for them to search through up to 5 files than it would be for 20. the DRY principle is good, but i’d argue the STFU (shut the frick up) principle is approximately as important, and code fragmentation (not to be confused with decoupling, by the way) should not be the default option in every case unless you’re writing enterprise level software.

Please modify this to clarify that Instance Global means something like:

local statObject = Instance.new("NumberValue")
statObject.Name = "StatValue"

As opposed to:

-- In a ModuleScript named StatValue
local value: number = 0
return {
  Get = function() return value end,
  Set = function(n) value = n end,
}

Just sketching some ideas down.

I don’t think you understand, this Post is not about my session data example, its more about small systems such as said system that what is the true difference between coding them in a Server Script and Module.


This also applies to what I mentioned previously. But to add on; I like using the Value Instances or Attributes because doing this kind of system in a Module would be quite tedious, especially when you need to access a Value requested by the Client, so you would need (this brings me to something else, all this time I’ve been saying RemoteEvent for getting a Value, it would be a Remote/BindableFunction actually, my mistake sorry) a RemoteFunction to return that Value.


The first piece of code is actually quite good, I didn’t think of RunService to be honest, BUT, and this is a big BUT, if you declared the LocalPlayer as a variable that would end up erroring if requested from the Server, thus breaking the Module. But in saying this, couldn’t an Exploiter access the Module and bypass that check anyway? Since having a shared Module can be edited by an Exploiter, so they would be able to bypass this and change the Value.


As for the rest of your reply, I’ll keep it in mind for now, I haven’t fully read it as it’s a lot… I’ll edit this reply or make a new one once I have fully read it with answers.

Thanks for your feedback! :slight_smile:

1 Like

I know this isn’t a reply to me, but could you explain to me further on this? I’m not quite sure what your saying.

I’m sure most people know what the “Instance Global is”… I don’t think that’s entirely necessary.


Not sure what you’re saying after this point.

I think you’re talking about storing numbers in a ModuleScript instead of using Rōblox objects (the ones you find in Explorer).

I’m giving guidance on how you can re-write your original post for clarify.

Yeah, LocalPlayer cannot be declared inside the module, it has to be passed as an argument to the individual functions


Exploiters can do anything on the client, but they cannot modify the “server” version of the module. So your sanity checks that are ran on the server side cannot be tempered with, and that is where you put your protection. There is basically no difference between the example code I gave, and your typical RemoteEvent, when it comes to protecting against exploiters, in both cases you have sanity checks running on the server, and well the client does what it wants. I guess the client has access to server sided code that would usually be hidden, but that’s not much of a concern

Even if the exploiter tries to run the functions that are meant to be server sided, chances are it wont work because they only work on the server, or well, the exploiter is able to run it, but it’s no different to the exploiter writing code himself and running it. Exploiters can only mess with their client side, the rare properties that are replicated from client to server (like some character stuff), and remotes

Ohh! No no, sorry, I’m more talking about whether it is necessary making small systems into Modules, rather than a regular Server Script. Sorry if it’s confusing. You see what I mean?

1 Like