Skip to content

Move listener queries SQLite on every PlayerMoveEvent, even with no teleport pending #46

Description

@milanmalhotra

Problem

PlayerMoveWhileTeleporting runs a SQLite query on every PlayerMoveEvent. Bukkit fires that event many times per second for every online player who is walking or just turning their head, and each time the listener does:

Dao<TeleportAttempt> tad = new TeleportAttemptsDao();
TeleportAttempt ta = tad.get(event.getPlayer());

(src/main/java/com/samleighton/sethomestwo/events/PlayerMoveWhileTeleporting.java lines 19-20), which is a synchronous select * from player_teleport_attempts where player_uuid = ? on the main thread.

A teleport attempt only exists for the few seconds of a /home countdown, so on a normal server almost every one of those reads returns nothing. The cost scales with player count and movement, not with teleports. It shows up clearly with debugLevel: info, where the console fills with the statement several times a second while a single player walks around, but the queries run just the same at the default error level; they are only invisible.

Not a bug in behaviour (cancel-on-move works), a performance and hygiene issue that would get worse on a busy server.

Proposed direction

Keep an in-memory set of player UUIDs that currently have a pending teleport attempt, and make the move listener return immediately unless the player is in it, so the database is only touched during an actual countdown.

  • Add to the set where Home.teleport saves the attempt (teleportAttemptsDao.save(new TeleportAttempt(...))), remove it wherever the attempt is deleted: completed teleport, cancelled by movement, onDisable cleanup, and the stale-attempt purge in onEnable.
  • PlayerMoveWhileTeleporting checks the set first, then falls through to today's DAO logic (TeleportAttempt.canTeleport is computed from the saved start location, so nothing else changes).
  • The player_teleport_attempts table stays as the source of truth so attempts still survive a restart the way they do today; the set is only a fast pre-check.
  • MockBukkit test: a player with no pending attempt moving triggers no query (assert via a counting hook or by observing no STMT log line), and the existing cancel-on-move test still passes.

Optionally, when cancelOnMove is false the listener already returns before the query, so no change there.

Acceptance criteria

  • With one player walking and no teleport in progress, debugLevel: info shows no player_teleport_attempts statements from the move listener.
  • Cancel-on-move still cancels a countdown when the player moves, including after a server restart with a stale attempt cleared on startup.
  • MockBukkit suite passes with Skipped: 0.

Found while doing the in-game check for #29 (bStats metrics); unrelated to that branch, which does not touch this listener.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions