Creating Sanity Check For Mining System?

I’m creating a mining system for my game, but it has to go through a RemoteEvent in order to send the ore to the player’s inventory.

I don’t want exploiters to be able to fire the RemoteEvent with a script and give themselves as much of the ore as they want, so what would be the best way to go about making a Sanity Check for this?

Conditions

  1. Player must be touching a Rock or the Ground with their legs
  2. Player must not be in Hub
  3. Suspiciously quick amount of item collecting should be detected

The problem I’m having is finding a way to program these conditions. I tried checking to see if the player was Touching the ground or rock with their legs first, but that didn’t work, since if the player is still after mining then the script will still think that player is exploiting.

local function MiningCheck(Plr)
	Plr.Character:WaitForChild('Right Leg').Touched:Connect(function(part)
		if part.Name == "Rock" or "World1" then
			return true
		else
			Plr.Character:WaitForChild('Left Leg').Touched:Connect(function(part1)
				if part1.Name == "Rock" or "World1" then
					return true
				else
					return false
				end
			end)
		end
	end)
end



CollectItem.OnServerEvent:Connect(function(Player,ID)
	
	print(Player.Name ..' has an item loading in...') --Debugg
	local ItemPos = ID
	print('Item ID ='.. ItemPos) --Debugg
	local AttributeCount = table.getn(Items[ID])
	print(AttributeCount ..' Attributes')

	local Attributes = Items[ID]
	local ItemName = Attributes[1]
	print('Item Name='.. ItemName) --Debugg
	local ItemValue = Attributes[AttributeCount]
	print('Item Price='.. ItemValue) --Debugg
	local ItemDescription = Attributes[AttributeCount - 1]
	print('Item Desc: '.. ItemDescription) --Debugg
	local Methods = {}

	for i,v in pairs(Attributes) do --Adds item attaining methods to table
		if i > 1 and i < AttributeCount - 1 then
			if v == "Mining" then
				local SanityCheck = MiningCheck(Player) --Sanity Check
				if SanityCheck == true then
					table.insert(Methods, 1, v)
				else
					print('Player is possibly exploiting')
				end
			end
		end
	end
	
end)
3 Likes

You could add a simple magnitude check, since the player can probably be jumping around while mining. You can also look if the player has the tool equipped, if it’s a normal tool.

2 Likes

The mining uses a simple Proximity Prompt, and the player cannot move while mining. Is there any way I can check if the player has used the Proximity Prompt (the RemoteEvent triggers after the proximity prompt is used).

Are you checking to see if a Proximity Prompt has been Activated in a local or a server script? If it’s a server script, you could add a player specific debounce to the activated function to prevent a player from triggering multiple prompts within a given time.

The Proximity Prompt’s activation is checked through a Local Script, which fires a RemoteEvent to a Server Script (this is to prevent exploiters from altering the Inventory Script).

I think it would be better to have the prompt activation be handled on the server, but it doesn’t make too big of a difference.

Your first check can be done by getting the player’s root part position and finding the distance to the rock they are mining. Example: (Rock.Position - RootPart.Position).Magnitude <= MaxDistance. This check fails if they are too far away from the rock.

If you want to see if a player is in a given area, you have some options. BasePart:GetTouchingParts() will give you a table of all the parts touching a specific part. This can be utilized by creating a part to represent the area of the hub and seeing if the player is touching that.

A cleaner option would be to create a Region3 using that part and use the workspace:FindPartsInRegion3WithWhitelist. The way I use this is to make the whitelist a table containing only the player’s root part.

Your final check can be acomplished using a table of debounces. When your function is fired, check if an entry in the table exists, such as table[Player.Name…" Debounce"]. If it does not, create it and carry on with the function. Once you are finished, set that entry to nil.

1 Like

I really like the sound of the Region3 idea, but this will be the first time I’ve ever worked with them. Do you have any material recommendation I can use related to this topic?

You can read more about the documentation here:

Region3.new() takes two Vector3 values as input. One is the minimum point and the other is the maximum. Respectively, these can be calculated as (Part.Position - Part.Size / 2) and (Part.Position + Part.Size / 2)

2 Likes

Have u ever tried just using Manhatten distance? It operates just like regions in this scenario but is much easier to implement

In your game do you mine lots of blocks like in mining simulator or minecraft? Because it really depends on the type of mining what kind of a sanity check system you would like to implement.

The mining is done at randomly placed ore nodes on the map, so there isn’t a lot of mining to do since its going to be an optional activity (the material from mining will be used to craft cosmetics).

Ok. In that case you probably would only want a distance check. It would be something like this

if Plr.Character and Plr:GetDistanceFromCharacter(Ore.Position) < MaxActivationDistance * 1.5 then
-- // Your code
end

Also do you want a time check?

1 Like

But be sure to multiply the max allowed distance by 1.5 as players who lag might have issues if it is too small.

  1. Check magnitude of player and the block you are mining.

  2. You are already checking if they are next to block.

  3. Add a debounce to your remote event using DebounceLib module or something else.

1 Like

I think that is a bit unnecessary. If the player is close to the block I don’t think they can be also close to the hub. They can only be in 1 position at a time.

1 Like

Also one cool thing to keep in mind you can do Plr:GetDistanceFromCharacter(POSITION) to get the position of a player relative to a position instead of doing (Pos1- Pos2).Magnitude. But remember to check if the player has a character because if they don’t then it will return 0

Thanks, this worked! But I used DistanceFromCharacter() instead. Was it changed from GetDistanceFromCharacter() to DistanceFromCharacter()?