How do I reliably detect what a character is standing on?

I’m writing a movement anti-cheat that operates entirely on the server for my games. This anti-cheat features anti-teleporting/speeding, anti-flying, anti-no-clipping, and anti-spin-attacking.

My problem with the anti-flying part is I’m having a difficult time reliably detecting whether the character is standing on something.

Solutions I’ve Tried

I’ve looked at Humanoid.FloorMaterial, but as the below screenshot shows, an exploiter can fake the property by creating a client-side part beneath themselves.

I’ve looked at a raycasting solution, but the problem is it can miss an object even if a player is legitimately standing on it, like with thin parkour bars, or the rare situation where a player is barely standing on a ledge for bragging rights.

image

4 Likes

Oh. I forgot to list that as another thing I’ve tried. It doesn’t work that well because it detects everything in the region below the player, including normally-unscalable walls that they might be flying next to. This happens because the function is constrained to a voxel grid of 4x4x4 cubes, and will automatically expand the arguments to compensate, which will would be far beyond just-below the legs.

Edit:

On second thought, I did a scripting experiment. The function seems to be no longer constrained to a grid. (Previously, the wiki said it constrains to grids.)

2 Likes

Magnitude can help, but this is a bit taxing.

What you could try doing is firing off several tens of downcasts around the character instead of a single one from the root and check each ray for where it ends up and what it’s hitting, as well as if the character’s current positions or whatever match the data that the server finds. An example of what I’m talking about, albeit client-sided, is Luanoid:

How you would apply this in practice though? I don’t exactly know. I don’t think there would be much utility in you checking if a sufficient amount of raycasts are around an average height because then users moving legally might get flagged frequently.

1 Like

That might pose some problems because you would be using a large amount of raycasts which would inevitably end up lagging your server… also it isn’t necessarily guaranteed to work (though the use cases where this wouldn’t work would be basically non-existent)

What you could do, though, is detect the region below the character’s legs and if a part exists there then you’re set.

That gives me an idea: I think what will work is if I checked a Region3 around a player, and then fired two raycasts towards each object.

The first raycast for each object would be done sideways on the XZ coordinates up to a certain distance, towards the target’s center XZ position on the same height. If the resulting normal is pointing up, then it passes, otherwise, if the normal is pointing down or sideways (like if a wall was hit), fail the check for that object. If nothing was hit, it would raycast again from that point downwards to a reasonable depth to see whether the object is not out of reach.

image

1 Like

The engine is capable of firing off hundreds of rays every frame with no impact on performance at all. The expense of raycasts comes primarily from how long they are. As for whether it works or not, I only posted something hypothetical for the sake of generating ideas: I don’t know how to do what OP’s requesting so I’m otherwise quietly tracking discussion on the topic.

1 Like

Although I haven’t tested this in a while, I once created an 8x8 mirror which would fire 64 raycasts per frame (their distance was capped at 20 studs) and make it appear in a surfaceGui (Did this in 2018?), resulting in less than 15 fps.

So… unless that’s changed I don’t think a player’s gameplay experience would be optimal if you were firing off rays every frame.

Yeah, doesn’t really help when you provide outdated and uncertain information. Short rays have never been expensive and you are capable of firing off hundreds of them per frame. You can achieve many different systems with this such as raycasting hitboxes (which resources for do exist now).

Your expense most likely came from trying to update the SurfaceGui as a form of creating a mirror because now you’re introducing the Gui engine to update and re-render a Gui in 3D space. Updating a Gui incurs some cost; updating it frequently and massively forces it to re-render every frame, which is a set up for terrible performance. Static Guis are more performant and changes help out with this.

With newer methods released for better creating these kinds of systems (e.g. literal mirroring, ViewportFrames with upcoming WorldModels and whatnot), LuaU optimisations not existing back in 2018 and Gui improvements done early this year, things will have changed since then. That’s in regards to updating the SurfaceGuis though; the point of raycasting remains unchanged.

Feel free to send me a message if you’d like to discuss further. Let’s remain on-topic.

1 Like

I think the FindPartOnRayWithWhitelist function would be really fast because with a small list generated with FindPartsInRegion3, it only has to sort through a few parts.

I just re-tested this, and my results are as follows:

  • Performance starts being affected at around 750-3000 raycasts/frame
  • The magnitude of the cast determines how many raycasts can be performed before performance is impacted (~750/frame for 500 studs, ~1750 for 100 studs, ~3000 for 5 studs)

So, your previous statement seems to be correct, but still this is the limit for a server per frame, and given that a game will have other threads being run, this limit will more than likely be significantly lower.

That being said, I don’t think firing a couple rays per frame per player will have any huge performance impact… though I don’t think it’s totally necessary in this scenario to use raycasting at all.

The chances of you casting from the server every frame are very far and few. Most often you’ll be doing this from the client. In the response I provided I did mention the server being the one to perform the casts but the rays you fire off are not enough to hit even 50 casts per frame, let alone any “maximum”.

If you don’t believe using raycasting is necessary at all, what do you think should be done? I’m having a hard time trying to figure out what the server can do to accurately determine what a player is standing on without the client actively being able to tamper with the results just by manipulating their own physics.

Raycasting isn’t unnecessary, it’s frankly the only way I can think about accomplishing this and it’s a valid way to do so at all. The question is how to apply the raycasts in such a way that they can form a sort of net below the player so the server is able to get what the player is on and from there determine if where they’re standing is legal or not.

1 Like

Given that we’re trying to detect whether or not a player is flying, and we just want to reliably know whether or not the player is actually standing on a part, we can use a combination of checking the FloorMaterial (to see whether it is air), and checking if there is a part directly below the player using FindPartsInRegion3.

This reason I suggest this is because it doesn’t matter if the player is say flying 0.5 studs above the ground, because it would be as though they’re not even flying at all, and @ForbiddenJ already has methods for anti-teleport/speeding/etc, so those checks would make sure they aren’t moving too fast. The point of this part being that we don’t have to be 100% accurate, we just have to be close enough.

FloorMaterial can’t be used because it’s detected by the client. There is an image right in the OP showing what the server will read FloorMaterial as from a client standing on a locally created part. The image shows FloorMaterial being read off as Plastic because the client is standing on an invisible part it created on it’s end, but the server does not see that part.

I’m not too sure about how a Region3 would work so I can’t make any comments in that respect. I’m neither the thread creator or someone who’s attempted to use Region3 to detect what’s under a player.

1 Like

This post about raycasting got me thinking of a variety of ways to detect the platform below the player:

This is what I came up with:

  1. Do raycast straight to object center.

    Best for balls and short, thin rods most often.

  2. Do XZ raycast, then -Y raycast.

    Best for tall blocks where players stand on ledges, or really large floors where walls possibly block the first few raycasts, or shapes that players could be inside of.

    image

  3. Do Raycasts towards the closest points reachable in each XYZ coordinate where two other coordinates are CFramed and locked to the part’s center.

    Best for ridiculously long objects, like long and thin rods, or path blocks that are really long.

3 Likes