What is the safest way to require module scripts on local scripts with ought them being exploited?

Im making a Quest System. I have 3 module scripts containing the quest info. linesMod script stores text(strings) the quest giver is supposed to say. the questMod contains the rewards. and funMod loops through the lines.



The server script down below is in workspace. Its requiring all 3 modules to run. When a player has stepped on a part, the script below shows the text, checks to see if a player has a quest, if there on a quest, and if it has been complete. It also rewards the player when they are done.

The problem is whenever a player steps on the part the text that the quest giver is displaying shows to the whole server.

I want the script below to run on a local script so the quest giver is displaying different text for each individual person whenever that player clicked a part.

But im worried about exploiters. If i put the code below on a local script. im worried the player can see my module script questMod and change the exp and gold. How do I go about handling my modules on a local script so that they are safe from exploiters

local funMod = require(game.ServerScriptService.funModScript)
local billsMod = require(game.ServerScriptService.linesModScript)
local questMod = require(game.ServerScriptService.questModScript)
local Triggered = script.Parent
local debounce = true

local qGui = game.Workspace.Bill.SignModel.SignPart:WaitForChild("qgPartGui")
local showTitle = qGui.mainFrame.questTitleLabel
local showQuest = qGui.mainFrame.questLabel

Triggered.Touched:Connect(function(hit)

	local char = hit.Parent
	local humanoid = char:FindFirstChild("Humanoid")

	if debounce and humanoid then
		debounce = false
		local plr = game.Players:FindFirstChild(char.Name)
		local pStats = plr:WaitForChild("leaderstats")
		local pVars = plr:WaitForChild("PlayerVars")
		local PlayerStats = plr:WaitForChild("PlayerStats")
		local pBeli = PlayerStats:FindFirstChild("Beli")
		local pExp = PlayerStats:FindFirstChild("Exp")
		local pOnQuest = pVars:FindFirstChild("OnQuest")
		local pQuestComplete = pVars:FindFirstChild("QuestComplete")
		local pRewardPaid = pVars:FindFirstChild("RewardPaid")
		local pExpPaid = pVars:FindFirstChild("ExpPaid")
		local pDone = pVars:FindFirstChild("QuestsDone")
		local thisQuest = "quest"..tostring(pDone.Value)
		local pItem = pVars:FindFirstChild("QuestItem")
		local totalQuests =	funMod.CountLines(questMod.Quests)

		if pOnQuest.Value then -- player has a quest
			if pQuestComplete.Value then -- player has completed the quest
				if not pRewardPaid.Value then -- give player their reward
					local allLines = billsMod.BillsLines[thisQuest].complete
					local numOfLines = funMod.CountLines(allLines)
					funMod.RunLines(allLines, numOfLines, showQuest, showTitle)

					pBeli.Value = pBeli.Value + questMod.Quests[thisQuest].reward
					pExp.Value = pExp.Value + questMod.Quests[thisQuest].Exp

					pRewardPaid.Value = true

					pExpPaid.Value = true

					pOnQuest.Value = false

					pDone.Value = pDone.Value + 0

					if pDone.Value < totalQuests then -- there is another quest
						pQuestComplete.Value = false
						pRewardPaid.Value = false
						pExpPaid.Value = false
						pOnQuest.Value = false
					else -- there are no more quests
						pDone.Value = 0
					end

				end -- end pRewardPaid
			else -- player has a quest, but not complete
				showTitle.Text = questMod.Quests[thisQuest].title
				local allLines = billsMod.BillsLines[thisQuest].onQuest
				local numOfLines = funMod.CountLines(allLines)
				funMod.RunLines(allLines, numOfLines, showQuest, showTitle)
			end -- end pQuestComplete
		else -- give player a quest

			pOnQuest.Value = true
			pItem.Value = questMod.Quests[thisQuest].item
			showTitle.Text = questMod.Quests[thisQuest].title
			local allLines = billsMod.BillsLines[thisQuest].allLines
			local numOfLines = funMod.CountLines(allLines)
			funMod.RunLines(allLines, numOfLines, showQuest, showTitle)
		end

		wait(5)
		debounce = true
	end
end)

When the player is loaded, or when they step on a part send a RemoteEvent to the client to update the part locally. You could also use a RemoteFunction to invoke the server to get the info though that’s up to you but make sure to add some sort of rate limiter so the remote can’t be spammed

In your case, the bytecode of the module script is never replicated to the client, hence they can’t even see or read the code at all.
This is because your module is required by a server script, therefore it acts like one, too.

You mentioned local script but I don’t see what you mean here. Your module is not accessible for a local script due to where it is located (ServerScriptService), the contents inside of that service is not replicated to the clients.

I mean if i were to put the module scripts in replicated storage. and put my server sided code into a local script. I want to do this so a gui gets cloned to the player who clicked a part. So the gui displays different text for each individual different player who clicked the part.

You are worried that they can modify the text on their own client?

If you put the module into ReplicatedStorage you can access it from the server and the client.

yes. I dont want them giving themselves more exp and gold

Well they can’t really unless you start handling gold and exp on the client itself.

They won’t be able to if you never rely on the value being sent from their client.
Never rely on a value being sent from the client, do every sanity check on the server side.

Values changed on the client-side is not replicated and can’t get picked up by the server, just FYI, if you didn’t know.

Yeah I know I’m just saying that unless he’s handling the values on the client it can’t really be exploited since I’m assuming each time a quest action has been complete he is sending a RemoteEvent to the client to update his current quest, of course, any RemoteEvent will need to be sanity checked and also rate limited.

1 Like

So the line

pBeli.Value = pBeli.Value + questMod.Quests[thisQuest].reward
pExp.Value = pExp.Value + questMod.Quests[thisQuest].Exp

is what im most worried about. cause i think someone could just do pBeli.Value = pBeli.Value + 1000000.

The value pBeli is on a serverscript. So would this be an example of me relying on the value being sent from their client?

Basically use the server to validate and check and only compare quest progress with player progress on the server. Simply use the module as read-only for the client, so it can display UI etc

1 Like

Ok i edited it now read it i confused myself for a sec lol but i want to make sure we on the same page

Have the server keep tracks of the rewards and such.
Client shouldn’t be able to have any control over it, it should only be able to read the value, nothing more.

1 Like

ok thank you that helps alot and hurts my brain alot less

2 Likes