v1 is outdated and unsupported, we highly recommend users checkout the greatly improved v2 instead:
v1 (outdated)
ZonePlus v1
Zone+ is a lightweight application that utilises regions and raycasting to efficiently determine players within an area.
Theory
View
This kind of question has popped up a lot of times over the years so I thought I’d finally address it:
What’s the best method of retrieving players within an area/zone on the server?
Common solutions
-
"Using touched/untouched events!" - This was actually how I handled zone checking when I first began developing. Not only do these work incorrectly (untouched often fires before touched, untouched sometimes never fires at all when leaving a part, etc) but they can cause lag when complex shapes enter them.
-
"GetTouchingParts!" - The one major flaw with this function is it doesn’t work with uncancollided parts. If the player jumps off the part, they won’t be registered. buildthomas and evaera have created a solution for this if you’re interesting in exploring this path.
-
"Magnitude checks!" - Sorry circle worshippers, but the square lovers are going to have something to say here.
-
"Region3" (by itself) - Polgons hate him. Scientists at Cambridge university have found out… no.
-
"Raycasting" (by itself) - Fire ray below player’s character, check if part below, bam! Polygons and circles are happy bunnies now. Shame the server isn’t. This method is fine for small servers, but fails to scale effectively for servers with increasingly larger amounts of players with recursive checks.
The holy grail
Region3 + Raycasting
Method
-
Setup a group of parts to represent your zone
-
Calculate the maximum and minimum boundaries of this zone
-
Create a Region3 value using these bounds
ᅠᅠᅠᅠᅠ
-
Get players in this region using FindPartsInRegion3. This function returns a list of parts, which you can use to check for a player’s character.
-
For the players returned in the region check, fire a ray below from the HumanoidRootPart (not too far as this causes lag). If one of the zone’s parts is returned, we can safely say the player is within that zone.
Benefits
-
No need to unnecessarily check every player within the server. Simply calculate a ‘rough’ area and determine who’s in the exact zone for players within that region.
-
Region3 and raycasting are ‘light-weight’. You can run these multiple times a second with minimal effect to performance.
Example Uses
Safe Zone (using additionalHeight, a loop and 2000 randomly generated parts)
Safe Zone (using uncancollided parts and zone events)
Coin Spawner
Voting Pads
Ambient Areas (client-sided)
https://thumbs.gfycat.com/TangibleFamiliarBufeo-mobile.mp4
Installing & Using
To learn how to install and use Zone+, visit the about section of the docs: https://1foreverhd.github.io/HDAdmin/projects/zoneplus/about/#example-server-sided
See For Yourself!
You can play around with open source examples here:
Best Practices
Zone+ provides an efficient way to determine players within an area, however should be used with consideration and is not always the optimal solution:
-
On the server, zones should be relatively small areas (ideally no more than 200x200x200), otherwise Region3 checks begin to become expensive. Minimise the volume of your zones where possible.
-
On the server, Zones should not be used extensively and should not cover a large proportion of a map. Zone+ is optimised for minimal, small zones. If you wish to cover a lot of your map, instead consider setting up zones on the client, or creating your own system which fires a ray from all players instead of performing additional unnecessary Region3 checks.
-
When using zone events (and calling
:initLoop()
or:initClientLoop()
), or calling your own loop, keep the amount of calls per minute to a minimum. By default when:initLoop()
is called (with a default delay of 0.1), 600 checks will be performed per minute. Instead, by specifying a delay of 3 seconds (i.e.:initLoop(3)
) only 20 checks will be performed per minute). Obviously the greater the delay, the greater the potential period it takes for a zone to detect a player entering or exiting. -
On the client, when using events call
initClientLoop()
instead ofinitLoop()
for situations where you only intend to check for the local player (e.g. in a local sound system). This method bypasses the zones default region3 checks which are unnecessary for most situations on the client. -
On the client, a raycast is fired for every zone. (i.e.
ray*zone*(1/delay) per second
) due to its object-like nature. While this has a negligible impact on performance, creating your own system which simply fires a ray every delay from the local player’s HRP is more efficient (i.e.ray*(1/delay) per second
instead)
Resources
Zone+ is actively maintained by the HD Admin Team; feel free to report bugs, suggest features and make pull requests at our repository.
Credit
Special thanks to:
- @DanzLua for their TypeScript Port of Zone+
- @H_mzah for assistance with the source control and automation, and additional ideas
- @Abbaok_origin for the Coin Spawner suggestion, and additional ideas
- @TheRings0fSaturn for the enhanced boundaries idea
- The DreamCraft team for assistance with the theory