My struggle with module script - How to pass a function in the module script?

So after going through a few tutorials on Youtube regarding module script I have tried my best to write scripts (especially so exploiters can’t manipulate the leaderboard) I have outlined my entire process here: Module Script Problem - Obsidian Publish as its just easier for me in terms of noting down and diagramming etc… so apologies for the external link. But as per this link in short this is what I am trying to achieve and any advice on this would be much appericiated.

  1. Player jumps in air
  2. Via module script (so score can’t be manipulated by exploiter) a function detects jump and adds 1 point to the roblox leaderboard.

As you can see my logic for doing this works, what don’t work is trying to do it more server side / within a module script to prevent exploitation / manipulation of the score. That is what I mainly need advice on going forwards as what I have tried so far produces zero errors so I am a bit stuck, it simply and literally does not work as intended. Overall how do I pass the jump score function into the module script?

I know you’re looking for something else but:

The exploiter can still manipulate the constants/variables in the module script using the debug library. You should just keep all the important logic in the server like this:

--//Services
local Players = game:GetService("Players")

--//Functions
Players.PlayerAdded:Connect(function(player)
	local stats = Instance.new("IntValue")
	stats.Name = "leaderstats"

	local jumps = Instance.new("IntValue")
	jumps.Name = "Jumps"
	jumps.Parent = stats

	stats.Parent = player
	
	player.CharacterAdded:Connect(function(character)
		local Humanoid = character:WaitForChild("Humanoid")
		
		Humanoid.Jumping:Connect(function(isJumping)
			if isJumping then
				jumps.Value += 1
			end
		end)
	end)
end)

Also if you’re just looking for some more info on the exploit, it goes something like this:

local module = require(script.Parent.ModuleScript)

--//3 is the constant index and 100 is the value set
setconstant(module.playerJumpedModule, 3, 100)

(also nice website)

1 Like

When you say put it in the server what do you mean exactly by that? Can you be more specific? What folder etc…? Do I still do it as a module script?

Thanks, but its automatic published from https://obsidian.md its just easy to do that because I can show my thought process to people and what I have tried easier.

What I mean is that all the important logic should be done server-side, meaning there’s no way for the client to interfere with the logic. Try pasting my script into a script that’s in ServerScriptService. You shouldn’t use module scripts unless you’re using the same code over again.

That kinda works, I got it to the point where it adds a score on jumping but not every time I also have this script recently in StarterPlayer → StarterCharacterScripts so I think this could be effecting it, just not sure how its like the jump score is delayed?:

local canjump = true
wait(2)
if script.Parent.ClassName == "Model" then

	local character = script.Parent
	print(character.Name)
	character.Humanoid.UseJumpPower = true
	character.Humanoid.JumpPower = 0
	local function jump()
		if canjump == true then
			canjump = false
			character.Humanoid.Jump = true
			character.Humanoid.JumpPower = 100		
			wait(0.05)
			character.Humanoid.JumpPower = 0
			wait(1.5)
			canjump = true
		end
	end
	character.Humanoid:GetPropertyChangedSignal("Jump"):Connect(jump)
end

Update I just disabled this script entirely and it adds the jumps but still not on every jump, its delayed like that, I can’t work out how?

Your local script shouldn’t affect the server, I just made a mistake.
Here’s a more reliable check for when a player jumps: (switch out your server script with this)

--//Services
local Players = game:GetService("Players")

--//Functions
Players.PlayerAdded:Connect(function(player)
	local stats = Instance.new("IntValue")
	stats.Name = "leaderstats"

	local jumps = Instance.new("IntValue")
	jumps.Name = "Jumps"
	jumps.Parent = stats

	stats.Parent = player

	player.CharacterAdded:Connect(function(character)
		local Humanoid = character:WaitForChild("Humanoid")
		local jumpDebounce = false
		
		Humanoid:GetPropertyChangedSignal("Jump"):Connect(function()
			if Humanoid.Jump and not jumpDebounce then
				jumpDebounce = true
				
				jumps.Value += 1
				
				task.wait(0.5)
				jumpDebounce = false
			end
		end)
	end)
end)

That was fast I was nearly there myself with a similar solution haha, thanks! That works perfectly now, I just need to balance the timings with the jump delay

1 Like

No problem, if you have any more questions, feel free to ask.

Also, since I forgot to explain earlier, I added the debounce so that if an exploiter rapidly changes their jump value on their humanoid, the server will only add their jump if there is no debounce.

1 Like
wait(2)
if script.Parent.ClassName == "Model" then

	local character = script.Parent
	print(character.Name)
	character.Humanoid.UseJumpPower = true
	character.Humanoid.JumpPower = 0
	local function jump()
		if canjump == true then
			canjump = false
			character.Humanoid.Jump = true
			character.Humanoid.JumpPower = 65		
			wait(5.0)
			character.Humanoid.JumpPower = 0
			wait(5.0)
			canjump = true
		end
	end
	character.Humanoid:GetPropertyChangedSignal("Jump"):Connect(jump)
end

I am now having trouble with this seperate script, initially I just wanted it so the player can’t hold down the space bar, instead they have to do a key press each time for a jump, it seems no matter what timing I use on the jump delay, disabiling and the task.wait(5.0) (I changed to 5.0 as well) on the score script above there seems to be a way to up the score too quickly by holding down the spacebar.

I believe you have to use SetStateEnabled.

First off, change your server-script to this: (I added a longer cooldown)

--//Services
local Players = game:GetService("Players")

--//Functions
Players.PlayerAdded:Connect(function(player)
	local stats = Instance.new("IntValue")
	stats.Name = "leaderstats"

	local jumps = Instance.new("IntValue")
	jumps.Name = "Jumps"
	jumps.Parent = stats

	stats.Parent = player

	player.CharacterAdded:Connect(function(character)
		local Humanoid = character:WaitForChild("Humanoid")
		local jumpDebounce = false
		
		Humanoid:GetPropertyChangedSignal("Jump"):Connect(function()
			if Humanoid.Jump and not jumpDebounce then
				jumpDebounce = true
				
				jumps.Value += 1
				
				task.wait(0.7)
				jumpDebounce = false
			end
		end)
	end)
end)

Next, add a local script into StarterCharacterScripts:
image

In the local script, paste this:

--//Services
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")

--//Functions
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")

--//Controls
local jump = false

--//Tables
local Connections = {}

--//Functions
UserInputService.JumpRequest:Connect(function()
	if Humanoid.FloorMaterial == Enum.Material.Air then
		jump = true
		Humanoid.JumpHeight = 0
		
		Connections.FloorMaterial = Humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
			if Humanoid.FloorMaterial ~= Enum.Material.Air then
				Connections.FloorMaterial:Disconnect()
				
				jump = false
			end
		end)
	end
end)

UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.Space and not jump then
		Humanoid.JumpHeight = 7.2
		Humanoid.Jump = true
	end
end)

(just a small thing, but I just want to say that you are probably one of the most patient person on this forum lol)

Thanks a lot! Very much appreciated! That would have took me a long time to figure out haha.

1 Like

No problem. If you have any more questions, feel free to ask.