How would I go about making a sanity check for this?

  1. What do you want to achieve? Keep it simple and clear!
    I simply want a way to add a sanity check to this script

  2. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve looked at a lot of posts regarding sanity checks but none seem to fit my criteria

Server script:

local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

ReplicatedStorage.RemoteEvents.UpdateInventorySpace.OnServerEvent:Connect(function(plr, CritterName, CritterValue, CritterImage)
	local reginventorySlot = ServerStorage.RegInventorySlots.InventorySlot:Clone()
	reginventorySlot.CritterName.Text = CritterName
	reginventorySlot.CritterValue.Value = CritterValue
	reginventorySlot.CritterValueText.Text = "Price: " .. CritterValue
	reginventorySlot.CritterImage.Image = CritterImage
	reginventorySlot.CritterNameValue.Value = CritterName
	reginventorySlot.Parent = plr.PlayerGui.ScreenGui.InventoryFrane.Inventory
	reginventorySlot.Name = CritterName
		
	local regSellSlot = ServerStorage.RegInventorySlots.SellSlot:Clone()
	regSellSlot.CritterName.Text = CritterName
	regSellSlot.CritterValue.Value = CritterValue
	regSellSlot.CritterValueText.Text = "Price: " .. CritterValue
	regSellSlot.CritterImage.Image = CritterImage
	regSellSlot.CritterNameValue.Value = CritterName
	regSellSlot.Parent = plr.PlayerGui.ScreenGui.CCKennedyShop.SellingFrame.Frame
	regSellSlot.Name = CritterName .. "SellSlot"
		
	local inventorySlot = ServerStorage.RegInventorySlots.InventorySlot:Clone()
	inventorySlot.CritterName.Text = CritterName
	inventorySlot.CritterValue.Value = CritterValue
	inventorySlot.CritterValueText.Text = "Price: " .. CritterValue
	inventorySlot.CritterImage.Image = CritterImage
	inventorySlot.CritterNameValue.Value = CritterName
	inventorySlot.Parent = ServerStorage.Inventories[plr.Name]
	inventorySlot.Name = CritterName
		
	local SellSlot = ServerStorage.RegInventorySlots.SellSlot:Clone()
	SellSlot.CritterName.Text = CritterName
	SellSlot.CritterValue.Value = CritterValue
	SellSlot.CritterValueText.Text = "Price: " .. CritterValue
	SellSlot.CritterImage.Image = CritterImage
	SellSlot.CritterNameValue.Value = CritterName
	SellSlot.Parent = ServerStorage.SellInventories[plr.Name]
	SellSlot.Name = CritterName .. "SellSlot"	
	plr.inventorySpace.Value = plr.inventorySpace.Value + 1	
end)

Local script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Player = game:GetService("Players").LocalPlayer

local canHit = true

local db = 1

script.Parent.CritterHitterPart.Touched:Connect(function(thing)
	if thing.Parent.Name == "Cricket" or "GrassHopper" and thing.Name == "Head" then
		if canHit == true then
			canHit = false
			if Player.inventorySpace.Value < 5 then
				
				local CritterName = thing.Parent.Critter.Handle.CritterName.Value
				local CritterValue = thing.Parent.Critter.Handle.CritterValue.Value
				local CritterImage = thing.Parent.Critter.Handle.CritterImage.Value
				
				Player.PlayerGui.ScreenGui.Plop:Play()
				
				Player.PlayerGui.ScreenGui.CritterCaptured.Text = "You captured a " .. CritterName .. "!"
				Player.PlayerGui.ScreenGui.CritterCaptured:TweenPosition(UDim2.new(0, 0,0.8, 0), Enum.EasingDirection.In, Enum.EasingStyle.Linear, 1, true)
				
				ReplicatedStorage.RemoteEvents.UpdateInventory:FireServer(CritterName, CritterValue, CritterImage)
				wait(db)
				canHit = true
				wait(3)
				Player.PlayerGui.ScreenGui.CritterCaptured:TweenPosition(UDim2.new(0, 0,1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 1, true)
			else
					canHit = false
					ReplicatedStorage.RemoteEvents.InventorySpaceFull:FireServer()
					Player.PlayerGui.ScreenGui["Menu Error"]:Play()
					Player.PlayerGui.ScreenGui.Warning.Visible = true
					Player.PlayerGui.ScreenGui.Warning.Text = "Full Inventory Space"

					wait(5)
						
					Player.PlayerGui.ScreenGui.Warning.Visible = false
			end
			wait(db)
			canHit = true
		end
	end
end)

The local script is inside of a tool and whenever the tool detects that it hit a critter then it should fire the remote event and tell you what critter you collected.

The server script is what takes all the critters information and puts it into a inventoryslot clones it and puts it into everything needed.

So I just want to know how I could possibly make a sanity check so a exploiter can’t just make they’re own script and fire the remote event with the information needed giving themselves critters and items they’re not supposed to have. Thanks for reading! :smiley:

It’s not clear what “critter value” is, but it seems to just be a number pertaining to a specific critter?

UpdateInventorySpace.OnServerEvent:Connect(function(plr, CritterName, CritterValue, CritterImage)...

You’re trusting the client with a lot just from the interface you’ve chosen for the RemoteEvent. The player must send 3 pieces of information about a critter. You’re relying on each info to be correct and in correspondence with the others. It’d be bothersome (but possible) to verify that, but there’s a better way.

Instead of sending info about a critter, just send the critter itself. That way the server only has to verify that the critter exists and then it can gather the info itself. So change the remote call to

local Critter = thing.Parent.Critter
ReplicatedStorage.RemoteEvents.UpdateInventory:FireServer(Critter)

and the remote listener to

function isACritter(thing)
    if typeof(thing) ~= "Instance" then return false end
    if not thing:IsA("Model") then return false end
    if not CollectionS:HasTag(thing, "Critter") then return false end -- etc...
    return true
end

function invalidCritterWarn(Critter)
    warn(("UpdateInventorySpace.OnServerEvent: %s is not a valid critter!"):format(tostring(Critter)))
end

UpdateInventorySpace.OnServerEvent:Connect(function(plr, Critter)
    if not isACritter(Critter) then invalidCritterWarn(Critter) return end
    
    -- ... have a distance check as well    

    local CritterName = Critter.Handle.CritterName.Value
    local CritterValue = Critter.Handle.CritterValue.Value
	local CritterImage = Critter.Handle.CritterImage.Value
    ...

Dealing with “a Critter itself” instead of “information about a critter” has another advantage: knowing which critter it is, you can have whatever logic you want for sanity checks. For example, if characters are say 5 studs tall and critters are less than 5 studs tall, then you should probably reject the remote call if the player making the call is more than 5+5=10 studs away. If a critter should only be interacted with once, check that it hasn’t already been interacted with, or if there’s a time limit then enforce that. Etc.

Hope this helps

2 Likes

You can use spatial queries on the server-side to ensure that the player is actually touching the critter.

These may be of help to you:
workspace:GetPartBoundsInBox() Documentation: WorldRoot | Roblox Creator Documentation
workspace:GetPartBoundsInRadius() Documentation: WorldRoot | Roblox Creator Documentation

This won’t work that well if the critters are moving around as well, due to lag and latency and all that and you’ll have hit registration issues.

Here’s also a very useful resource. This YouTuber actually knows what he’s talking about unlike 90% of the tutorials on there. (I saw one that suggested to use clientside anticheats to stop speedhackers!)

I will be using this way of sanity checking. Thank you very much. I hadn’t thought about actually getting the critter instead of a bunch of values that’s defiantly a better way of doing it! thanks again.

I don’t think this would be an issue simply because after its interacted with it is destroyed haha.

The critters are moving around so I guess I wont try getting into all of that, but I’ll look into spatial queries and I’ll watch the video you provided, thank you.

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