78 Collection<Player> players,
79 LivingEntity liveTarget,
83 boolean showCountdown,
87 this.plugin = Objects.requireNonNull(plugin,
"plugin");
88 Objects.requireNonNull(players,
"players");
89 if (liveTarget ==
null && fixedTarget ==
null) {
90 throw new IllegalArgumentException(
"Either liveTarget or fixedTarget must be provided");
93 for (Player p : players) {
94 if (p !=
null && p.isOnline()) {
95 startLocations.put(p.getUniqueId(), p.getLocation().clone());
99 this.liveTarget = liveTarget ==
null ? null :
new WeakReference<>(liveTarget);
100 this.fixedTarget = fixedTarget ==
null ? null : fixedTarget.clone();
101 this.totalSeconds = Math.max(0, seconds);
102 this.secondsLeft = this.totalSeconds;
103 this.periodTicks = Math.max(1L, periodTicks);
104 this.showCountdown = showCountdown;
105 this.cancelOnMove = cancelOnMove;
106 this.moveToleranceSq = Math.max(0.0, moveTolerance) * Math.max(0.0, moveTolerance);
142 if (startLocations.isEmpty()) {
148 if (secondsLeft > 0) {
151 forEachOnlinePlayer(p -> p.sendActionBar(Component.text(
152 "Teleporting in " + secondsLeft +
" / " + totalSeconds +
"…"
158 final List<UUID> toRemove =
new ArrayList<>();
159 for (Map.Entry<UUID, Location> e : startLocations.entrySet()) {
160 Player p = Bukkit.getPlayer(e.getKey());
161 if (p ==
null || !p.isOnline()) {
162 toRemove.add(e.getKey());
165 Location
start = e.getValue();
166 Location now = p.getLocation();
168 if (!sameWorld(
start, now) ||
start.toVector().distanceSquared(now.toVector()) > moveToleranceSq) {
169 p.sendActionBar(Component.text(
"Teleport cancelled (you moved)."));
170 toRemove.add(e.getKey());
173 toRemove.forEach(startLocations::remove);
174 if (startLocations.isEmpty()) {
185 Location target = resolveTarget();
186 if (target ==
null) {
188 forEachOnlinePlayer(p -> p.sendActionBar(Component.text(
"Teleport failed: no valid target.")));
193 forEachOnlinePlayer(p -> p.teleport(target));