WS-Preventer - A fix to an annoying issue - V1.1

If you’re looking for help setting up, please scroll down.
If you’re making a bug report or a suggestion, please make sure it’s not already under Known Issues or Planned Features

Current Version: V1.1

V1.1 changes + Auto update checking
+ Better detection from different angles
+ Efficiency upgrade
+ General code cleanup (I wrote this at 1am so I wasn't going for the cleanest script when I made this originally)
+ New documentation

Background

Hi there! I’m 99% sure if you’ve been in any semi-popular roblox game as of late you’ve seen people doing something that I like to call “WSing” It’s also known as Ro-banging. This is where one person moves back and forth by spamming W and S behind another player, usually a girl. Even as a “joke” this is seen as weird and uncomfortable. This script aims to help manage this behaviour!

How it works

This works by watching a player’s movements and if it detects that a player is moving back and forth rapidly, it raycasts to see if a player is directly in-front or behind them

Setup

  1. Get the model from the Creator Hub and insert it into Server Script Service
  1. Edit the settings you wish to modify

  2. Profit!

Settings


local config = {

Tolerance = 2, --//The tolerance. Suggested value of 2. too low and you'll get false positives, too high and it won't trip

KillUser = true, --//Will it kill the user who is doing it?

Bypass = {}, --//A list of userids or names (case sensitive) who have bypass

IncludeDummies = {workspace.TESTRIG}, --//A list of objects which have Humanoids in them which are considered players. Good for testing on NPCs

VersionCheck = true, --//If true, this will use MarketPlaceService to automatically check to see if this is out-of-date

CustomDetectFunction = function(plr:Player)

--//A custom function which is called when an action is detected.

--//NOTE: If killuser is enabled, the player is killed before this function is called

return

end,

}

Tolerance

int

Default: 2

This describes how ‘lenient’ the script is. If it’s set too low, it’ll lead to false positives. If it’s set too high it won’t trigger properly. Internally this is used for distance checking, timing, and a few other variables

KillUser

bool

Default: true

If true, the user who is doing the action will be killed upon detection.

If true, this is ran BEFORE CustomDetectFunction

VersionCheck

bool

Default: true

If true, this will automatically check for updates and alert you if one is needed.

Bypass

list

Default: {}

This is a list of userids and usernames who can bypass detection.

Names are CASE SENSITIVE

IncludeDummies

list

Default: {}

This is a list of Models in the workspace which are considered player characters. Good if you want to test or if you have an NPC in your game.

The models MUST have a humanoid in them

CustomDetectFunction

function

Default: return

This is a function that is ran whenever a detection is made. It’s suggested to use this for public humiliation or logging with another system such as Adonis

If KillUser is true, this function is ran AFTER the user is killed

Known issues

  • If the user is really slow, the script won’t trip

  • if the user is in a different direction, the script won’t trip Resolved V1.1

  • If the user is angled a different way detection has a chance at failing Resolved V1.1

  • Somewhat inefficient - Work in progress

Planned Features

  • Automatically moving to Server Script Service if the script is in workspace Added V1.1

  • Module version for easy integration into pre-existing systems

  • General error catching/efficiency upgrades Added V1.1

  • Adonis plugin

  • Automatically validating your settings you set

FAQ

aka questions that have been asked or ones i forsee being asked

Q: Does ping/lag effect it?

Not too badly. I’ve tested this with a program called Clumsy which adds in artificial packet loss and network delay. Up to 600 miliseconds of ping the script still runs fine, albiet slow.

Q: Can it handle multiple players at once

Yes

Q: Why make this?

WSing is seen as weird and gross to a lot of people such as me. At the best it’s just irritating, at the worst is uncomfortable. As a personal anecdote I tend to use avatars with less skin showing to prevent this (among other things) but if a system like this exists I’ll be able to dress more freely on Roblox.

Contributors and License

Contributors

@Claym1x - Main developer

@driedfxrn - Ideas/raycast and detection improvements

@ZappyZooms - Suggestions/motivation

License/terms of reuploading

This project falls under the MIT License, basically meaning you can reupload this, modify it, and redistribute this under your own name. All I ask for is a bit of credit

23 Likes

This is actually a really good module honestly! I hope that more games start using this becuase literally every game I go in has atleast 5 people doing the same thing and it’s getting annoying.

2 Likes

Not a girl, but I understand this problem. It is inappropriate for the younger audience and it’s actually a good thing you made this.

Good job!

3 Likes

My friend group is cooked.

But in all seriousness, this is a great script… there’s nothing more to it, it’s just a generally great script that most games should have, I feel like you should be more clear on the installation because I thought I had to put it in StarterCharacterScripts, but instead it was a Server Script, additionally, I thought it automatically picked up all humanoids, not just players, so I had to tinker around a little bit until I found the dummy table.

But still, in total, this is a great contribution to the Roblox community! :+1:

2 Likes

Developers are coping by making resources like these over a roblox joke?

At that point just make it so players can’t even touch each other with big collider boxes

4 Likes

Thanks for the feedback!

Charlimt hdhxnxnxmskxjxnxnxn

1 Like

LOL, I actually have never thought i would see anything like this one day

2 Likes

Not sure what games you play but I have never seen anyone doing this “WSing” that you describe. Nonetheless if it is a problem you are facing and this solution works then great.:+1:

1 Like

go in games like “rate my avatar” and you will see a TON of them

2 Likes

Yeah I don’t play those games. Sounds like specific types of games attract players who do it.

1 Like

It’s sexual harassment. Among some friends it may be a joke, but I can’t see myself doing that to anybody else genuinely. This script would be good to prevent that!

2 Likes

It can realistically happen in any game. The game that I play the most and see it the most in (Pinewood computer core, pbcc) is just a generic sci fi game. Different games have a bigger issue but it’s so common there in comparison to how many concurrent players pbcc gets

1 Like

At the end of the day though is it really that deep you have to make a script to “defend” this 90% of the roblox audience don’t even understand what it means, and for the ones that do aren’t bothered by it you’re making it seem like a bigger issue than it actually is.

2 Likes

Labeling it as sexual harassment is perhaps a stretch. In most cases, it’s just a way to annoy someone or as a playful interaction, it ultimately depends on the Intent. I’m gonna speak completely from experience, but I’ve never really came across it that much, when I do, it’s just random people trying to be annoying to every player in a server. Even if it’s targeted towards someone dressing a specific way, it would still depend on a lot of factors for it to be labeled as “sexual harassment”, since this is Online, and not reality.

Good resource though, at least it adds a method to prevent it. Since it does get annoying if someone does it repeatedly.

7 Likes

excuse me but this is like saying t bagging someone is sexual harrasment because you are bringing your lower end closer to his face.

5 Likes
-- Configuration 
local config = {
	Tolerance = 2, 
	KillUser = true,
	Bypass = {},
	IncludeDummies = {},
	CustomDetectFunction = function(plr)
		
	end,
}

-- Storage var for tracking player movements
local storage = {}

-- Function to get all characters in the game
function getCharacters(excludePlayer)
	local result = {}

	-- Include all game players except the excluded player
	for _, player in pairs(game.Players:GetChildren()) do
		if player.Character and player.Name ~= excludePlayer.Name then
			table.insert(result, player.Character)
		end
	end

	-- Same for dummies
	for _, dummy in pairs(config.IncludeDummies) do
		if dummy and dummy:FindFirstChild("Humanoid") then
			table.insert(result, dummy)
		else
			warn("[ANTI-WS] -> Dummy " .. tostring(dummy) .. " does not exist or is not a character")
		end
	end

	return result
end

-- Function to do a raycast from the player's position
function raycast(player)
	local success, result = pcall(function()
		local character = player.Character
		local origin = character.HumanoidRootPart.Position + Vector3.new(0, 0, config.Tolerance / 2)
		local direction = character.HumanoidRootPart.CFrame.LookVector * (config.Tolerance * 2) * 4
		
		local params = RaycastParams.new() do 
			params.FilterType = Enum.RaycastFilterType.Include
			params.FilterDescendantsInstances = getCharacters(player)
		end

		local ray = workspace:Raycast(origin, direction, params)

		if ray then 
			return ray
		end

		-- Check back of player if no hit was found initially
		direction = -character.HumanoidRootPart.CFrame.LookVector * (config.Tolerance * 2) * 4
		ray = workspace:Raycast(origin, direction, params)

		if ray then 
			return ray
		end
	end)

	if not success then
		warn("[ANTI-WS] -> An error occurred in raycasting:", result)
	end

	return result
end

-- Function to check player movements
function process(player)
	local success, _ = pcall(function()
		local movements = storage[player.UserId]
		local lastState = "forward"
		local lastIter = 1
		local instances = 0

		-- Store movement
		for _, state in pairs(movements) do
			if state == lastState then
				lastIter += 1
			else
				lastState = state
				if lastIter < config.Tolerance * 2 then
					instances += 1
				end
				lastIter = 1
			end
		end

		-- Weird ah movement
		if instances > config.Tolerance * 2 then
			local rc = raycast(player)
			if rc then
				if config.KillUser then
					player.Character:WaitForChild("Humanoid").Health = 0
				end
				config.CustomDetectFunction(player)
			end
		end
		storage[player.UserId] = {}
	end)

	if not success then
		warn("[ANTI-WS] -> An error occurred in processing:", _)
	end
end

-- Event handler for when a player joins the game
game.Players.PlayerAdded:Connect(function(player)
	if not table.find(config.Bypass, player.UserId) and not table.find(config.Bypass, player.Name) then
		storage[player.UserId] = {}

		player.CharacterAdded:Connect(function()
			local lastTime = 0
			local hrp = player.Character:WaitForChild("HumanoidRootPart")
			local humanoid = player.Character:WaitForChild("Humanoid")
			
			-- Continuously check player movement
			while hrp and humanoid.Health > 0 do
				task.wait(0.05)  -- Frequency of checks

				if humanoid.MoveDirection.Magnitude > 0 then  -- Check if the player is actually moving
					local success, _ = pcall(function()
						local torVel = (hrp.Velocity * Vector3.new(1, 0, 1)).Magnitude
						local directionVelocity = Vector2.new(hrp.Velocity.X, hrp.Velocity.Z).Unit
						local dir = Vector2.new(hrp.CFrame.LookVector.X, hrp.CFrame.LookVector.Z).Unit
						local dotProduct = directionVelocity:Dot(dir)
						local angle = math.acos(dotProduct) * (180 / math.pi)
						local stateVal = (angle < 45) and "forward" or "backward"
						table.insert(storage[player.UserId], stateVal)
						
						lastTime += 1
						
						if lastTime == 10 then
							process(player)
							lastTime = 0
						end
					end)
					
					if not success then
						warn("[ANTI-WS] -> An error occurred in movement loop:", _)
					end
				end 
			end
		end)
	end	
end)

-- Event for when a player leaves the game
game.Players.PlayerRemoving:Connect(function(player)
	if not table.find(config.Bypass, player.UserId) and not table.find(config.Bypass, player.Name) then
		storage[player.UserId] = nil
	end
end)

Here’s some code that should fix the direction issue, and i just made it so the while event only fires if they are actually moving. Just making the code a little neat too.

5 Likes

This is a great module script! I won’t be using it for “wsing” but I will fork it for other things. Thank you!

This is an amazing resource, I applaud you. In one of my favorite games to play, Area-02, this so-called “ro-banging” happens a ton, especially by Xbox players. I’m not sure why the Xbox players love to do it so much.

1 Like

Thanks! Will def work in some of the stuff you added into V1.1 which I’m currently working on

2 Likes

Was this a real thing you decided to make with your time?
I can’t tell if this is sarcastic or not.

As someone else already said, labeling it as sexual harassment is most definitely a stretch.
Same as the whole t-bagging controversy from a bit ago.

7 Likes