Zones
A zone is a region plus the rules that apply inside it. Zones opened through the API behave exactly
like the ones defined in zones.yml, and both appear in /sh list.
The entry point
Section titled “The entry point”public interface SomaHider { ZoneBuilder hide(); ZoneBuilder hide(Region region); Collection<HiderZone> zones(); void refresh();}| Method | Does |
|---|---|
hide() | Starts building a zone that covers the whole server. |
hide(Region) | Starts building a zone bound to a region. |
zones() | Returns the zones currently open, yours and the configured ones alike. |
refresh() | Recomputes visibility now instead of waiting for the next pass. |
hide() with no region is a zone with no boundary: every online player is inside it. Use it for a
server-wide event rather than a located one.
refresh() is rarely needed. SomaHider already recomputes visibility a few times a second, and reacts
to joins, quits and teleports on its own. Call it when you have just changed something a custom rule
reads and you do not want to wait for the next pass. It is safe to call from any thread: off the main
thread it schedules the work rather than doing it inline.
Regions
Section titled “Regions”Region decides who is inside:
@FunctionalInterfacepublic interface Region { boolean contains(Location location);}A circle is built in:
Region arena = Region.circle(center, 40.0);It compares x and z against the centre and checks the world, so it is a cylinder with no height limit,
the same shape as a zone defined in zones.yml.
Any other shape is a lambda:
Region cuboid = location -> box.getWorld().equals(location.getWorld()) && box.contains(location.toVector());contains runs on the main thread, once per online player per pass. Keep it to arithmetic. Do not put
a database call, a web request or a lock in there.
Building the zone
Section titled “Building the zone”public interface ZoneBuilder { ZoneBuilder named(String name); ZoneBuilder disguise(DisguiseProfile disguise); ZoneBuilder disguise(ConfigurationSection section); ZoneBuilder duration(Duration duration); ZoneBuilder groupResolver(GroupResolver resolver); ZoneBuilder reveal(VisibilityRule... rules); HiderZone open();}| Method | Default when omitted |
|---|---|
named(String) | A generated name such as zone4. |
disguise(...) | The disguise section of config.yml. |
duration(Duration) | No expiry. The zone runs until you close it. |
groupResolver(GroupResolver) | A resolver returning null for everyone, so group rules never match. |
reveal(VisibilityRule...) | No rules. Everyone inside is hidden from everyone else. |
open() registers the zone and returns it. The zone starts hiding players on the next pass, a few
ticks later.
Give your zones a name you can recognise in /sh list, and make sure it does not collide with a zone
id from zones.yml: /sh stop <name> matches by name, ignoring case.
Group resolvers
Section titled “Group resolvers”@FunctionalInterfacepublic interface GroupResolver { String groupOf(Player player);}The group id is what Reveal.sameGroup() and its siblings compare. Returning null means the player
belongs to no group, and a null group is never revealed by a group rule.
groupOf is called during visibility passes, so keep it cheap. Reading a field or a cached map is
fine; querying a database is not.
Closing
Section titled “Closing”public interface HiderZone { String name(); void close();}A zone closes when you call close(), or on its own once its duration has elapsed. Closing releases
every player it was hiding, and the disguises they were given are forgotten.
Nothing closes your zones for you when your plugin disables, so close them in onDisable() if a
leftover zone would be a problem.
@Overridepublic void onDisable() { if (zone != null) { zone.close(); }}