EssentialsC API / Homes API

Homes API

Read, create, delete, and teleport players to their homes. Package net.godlycow.org.essc.api.home.

Overview

The homes module revolves around HomeManager. Data access is async (CompletableFuture, since storage is async); teleport state - cooldowns and pending warmups - is synchronous. Seven events cover the full home lifecycle.

Every home belongs to an owner UUID. Most read/write methods take the raw UUID so you can manage homes for offline players too.

Home

interface net.godlycow.org.essc.api.home.Home

Immutable snapshot of a single home. Homes are compared by (owner, name).

Method Returns Description
UUID getOwner()UUIDUUID of the home owner.
String getName()StringHome name, e.g. base.
String getWorldName()StringName of the world this home is in.
double getX()doubleX coordinate.
double getY()doubleY coordinate.
double getZ()doubleZ coordinate.
float getYaw()floatYaw rotation.
float getPitch()floatPitch rotation.
long getCreatedAt()longUnix timestamp (millis) when the home was created.
Location toLocation(Server server)LocationResolves the stored coordinates into a Bukkit Location.

Since Home stores raw coordinates, you can build the Location yourself, or let toLocation() do it:

HomeToLocation.java
// Option 1: one-call conversion.
Location loc = home.toLocation(server);

// Option 2: manual, e.g. to tweak coordinates first.
Location loc2 = new Location(
    server.getWorld(home.getWorldName()),
    home.getX(), home.getY(), home.getZ(),
    home.getYaw(), home.getPitch()
);

HomeManager

interface net.godlycow.org.essc.api.home.HomeManager

Get it via api.getHomeManager(). Data reads/writes are async (CompletableFuture); teleport state is synchronous.

Data access

Method Returns Description
boolean isHomeSystemEnabled()booleanWhether the homes system is enabled in the config.
CompletableFuture<Home> fetchHome(UUID owner, String name)HomeFetches a single home; completes with null if it doesn't exist.
CompletableFuture<List<Home>> fetchHomes(UUID owner)List<Home>Fetches all homes for an owner, including offline players.
CompletableFuture<Boolean> homeExists(UUID owner, String name)booleanWhether a named home exists for the owner.
CompletableFuture<Integer> getHomeCount(UUID owner)intHow many homes the owner has stored.
CompletableFuture<Boolean> setHome(Player player, String name, Location location)booleanCreates or overwrites a home for the player.
CompletableFuture<Boolean> setHome(UUID owner, String name, Location location)booleanSame, but works for offline players.
CompletableFuture<Boolean> deleteHome(UUID owner, String name)booleanDeletes a home; completes false if it didn't exist.
int getMaxHomes(Player player)intMaximum homes allowed for the player based on their permissions.
Collection<String> getCachedHomeNames(UUID owner)Collection<String>Names currently held in the in-memory cache (fast, may be stale).
void clearCache(UUID owner)voidDrops the cached home names for an owner.
void reload()voidReloads config + storage. Re-query anything you cached.

Teleports & cooldowns

Method Returns Description
boolean isOnCooldown(Player player)booleanWhether the player is inside the home teleport cooldown window.
long getRemainingCooldownSeconds(Player player)longSeconds left on the cooldown, or 0.
boolean hasPendingTeleport(Player player)booleanWhether the player currently has an in-progress (warmup) teleport.
void cancelTeleport(Player player)voidCancels the pending teleport (also cancels the warmup).
void startTeleport(Player player, Home home)voidStarts the teleport flow for a player to a home, firing the warmup + teleport events.

A typical async fetch - never block the main thread on the future:

FetchHome.java
HomeManager homes = api.getHomeManager();

homes.fetchHome(player.getUniqueId(), "base").thenAccept(home -> {
    if (home == null) {
        player.sendMessage("You don't have a home called 'base'.");
        return;
    }
    player.teleportAsync(home.toLocation(server));
});

Teleports & cooldowns

The flow: startTeleport()HomeWarmupStartEvent (cancellable, adjustable warmup) → HomeTeleportEvent after the warmup (cancellable) → player moves → HomePostTeleportEvent. Moving or logging out cancels the warmup and fires HomeWarmupCancelEvent.

StartTeleport.java
// Start the full teleport flow (warmup + teleport + events).
if (homes.isOnCooldown(player)) {
    player.sendMessage("Wait " + homes.getRemainingCooldownSeconds(player) + "s");
    return;
}
if (homes.hasPendingTeleport(player)) {
    player.sendMessage("A home teleport is already in progress.");
    return;
}

homes.fetchHome(player.getUniqueId(), "base").thenAccept(home -> {
    if (home != null) {
        homes.startTeleport(player, home); // fires warmup/teleport events
    }
});
startTeleport() is fire-and-forget. It fires the events; EssentialsC handles the actual warmup/ticking. Veto a teleport by cancelling HomeWarmupStartEvent or HomeTeleportEvent, or react after it completes.

Events

All seven home events live in net.godlycow.org.essc.api.home.event and extend org.bukkit.event.Event. Register listeners the usual way via org.bukkit.plugin.PluginManager.

HomeSetEvent - cancellable

Fired when a home is created or overwritten. Cancelling prevents the save.

HomeSetListener.java
@EventHandler
public void onHomeSet(HomeSetEvent event) {
    Player p = event.getPlayer();

    // Veto homes inside a protected region, with a custom reason.
    if (isProtected(event.getLocation())) {
        event.setCancelled(true);
        event.setCancelReason("Location is protected.");
        p.sendMessage("You can't set a home there!");
    }

    String homeName = event.getHomeName();
    Location loc = event.getLocation();
}

HomeDeleteEvent - cancellable

Fired when a home is deleted.

HomeDeleteListener.java
@EventHandler
public void onHomeDelete(HomeDeleteEvent event) {
    // Log every home deletion to a file.
    getLogger().info(event.getPlayer().getName()
        + " deleted home '" + event.getHomeName() + "'");
}

HomeTeleportEvent - cancellable

Fired just before the player is moved to the home.

HomeTeleportListener.java
@EventHandler
public void onHomeTeleport(HomeTeleportEvent event) {
    Home home = event.getHome();

    // Block teleports into unloaded/vanished worlds.
    if (server.getWorld(home.getWorldName()) == null) {
        event.setCancelled(true);
        event.setCancelReason("Home world is missing.");
    }
}

HomeWarmupStartEvent - cancellable

Fired when the warmup begins. You can lengthen/shorten it or cancel outright.

HomeWarmupListener.java
@EventHandler
public void onHomeWarmupStart(HomeWarmupStartEvent event) {
    // Double the warmup for players in combat.
    if (isInCombat(event.getPlayer())) {
        event.setWarmupSeconds(event.getWarmupSeconds() * 2);
    }

    // Give donors instant teleports.
    if (event.getPlayer().hasPermission("vip.instant")) {
        event.setWarmupSeconds(0);
    }
}

HomeWarmupCancelEvent

Fired when a warmup is aborted. getReason() is one of PLAYER_OFFLINE, PLAYER_MOVED, or EVENT_CANCELLED.

HomeWarmupCancelListener.java
@EventHandler
public void onHomeWarmupCancel(HomeWarmupCancelEvent event) {
    switch (event.getReason()) {
        case PLAYER_MOVED -> event.getPlayer().sendMessage("Teleport cancelled - you moved!");
        case PLAYER_OFFLINE -> getLogger().info("Home warmup dropped for offline player.");
        case EVENT_CANCELLED -> { /* another plugin vetoed it */ }
    }
}

HomePostTeleportEvent

Fired after the player has been moved to their home. Use it for welcome effects.

HomePostTeleportListener.java
@EventHandler
public void onHomePostTeleport(HomePostTeleportEvent event) {
    Player p = event.getPlayer();
    Location dest = event.getDestination();

    p.playSound(dest, Sound.BLOCK_PORTAL_TRAVEL, 0.5f, 1.2f);
    p.sendActionBar("Welcome home, " + p.getName() + "!");
}

HomeCooldownExpireEvent

Fired when a player's home teleport cooldown expires.

HomeCooldownListener.java
@EventHandler
public void onHomeCooldownExpire(HomeCooldownExpireEvent event) {
    // previousTeleportTime is the millis timestamp of the last teleport.
    long last = event.getPreviousTeleportTime();
    getLogger().info(event.getPlayer().getName() + " home cooldown expired");
}

Worked examples

Give every new player a starter home

StarterHome.java
@EventHandler
public void onJoin(PlayerJoinEvent event) {
    Player p = event.getPlayer();
    HomeManager homes = api.getHomeManager();

    homes.homeExists(p.getUniqueId(), "spawn")
        .thenAccept(exists -> {
            if (!exists) {
                Location spawn = p.getWorld().getSpawnLocation();
                homes.setHome(p, "spawn", spawn);
            }
        });
}

List a player's homes as formatted text

HomeListCommand.java
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
    if (!(sender instanceof Player p)) return true;

    api.getHomeManager().fetchHomes(p.getUniqueId()).thenAccept(homes -> {
        if (homes.isEmpty()) {
            p.sendMessage("You have no homes. Use /sethome.");
            return;
        }
        StringBuilder sb = new StringBuilder("Homes (").append(homes.size()).append("): ");
        for (int i = 0; i < homes.size(); i++) {
            if (i > 0) sb.append(", ");
            sb.append(homes.get(i).getName());
        }
        p.sendMessage(sb.toString());
    });
    return true;
}

Clean up homes when a player is banned

BanCleanup.java
@EventHandler
public void onBan(BanListEvent event) { /* not a real event - illustrative */ }

// Using a UUID lookup:
public void purgePlayer(UUID uuid) {
    HomeManager homes = api.getHomeManager();
    homes.fetchHomes(uuid).thenAccept(list -> {
        for (Home home : list) {
            homes.deleteHome(uuid, home.getName());
        }
        homes.clearCache(uuid);
    });
}