Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple queued TPA requests #3801

Merged
merged 85 commits into from
Dec 4, 2021
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
ca390cf
Housekeeping
JRoy Nov 28, 2020
5d785d9
Add support for multiple simultaneous tpa requests
JRoy Nov 30, 2020
1d1fd57
Add queue size limit
JRoy Nov 30, 2020
e30ba17
Fix inverted parameter in IUser#getNextTpaToken
JRoy Nov 30, 2020
56d65fd
Reduce message spam
JRoy Nov 30, 2020
5ec3e25
Add tab completions to tpaccept and tpdeny
JRoy Nov 30, 2020
f299421
Fix codestyle violations
JRoy Nov 30, 2020
7114475
Add back deprecated APIs + Add javadocs for IUser#getNextTpaToken
JRoy Jan 19, 2021
7d7d065
Abstract hasPendingTpaRequests into API
JRoy Jan 19, 2021
18d1f54
Change TpaRequestToken to TpaRequest
JRoy Jan 19, 2021
608ab16
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jan 19, 2021
ce57dd2
Fix small typo in javadocs
JRoy Feb 8, 2021
d7e485a
Merge branch '2.x' into feature/tp-accept-queue
JRoy Feb 20, 2021
11a0562
Merge branch '2.x' into feature/tp-accept-queue
JRoy Mar 6, 2021
4852780
Merge branch '2.x' into feature/tp-accept-queue
JRoy Mar 19, 2021
1b4f17d
Merge branch '2.x' into feature/tp-accept-queue
JRoy Apr 8, 2021
64048dd
Merge branch '2.x' into feature/tp-accept-queue
JRoy Apr 26, 2021
841727c
Merge remote-tracking branch 'origin/2.x' into feature/tp-accept-queue
JRoy May 10, 2021
2e74dac
Typo
JRoy May 10, 2021
7172ac6
Merge branch '2.x' into feature/tp-accept-queue
JRoy May 13, 2021
1e39a1a
Merge branch '2.x' into feature/tp-accept-queue
JRoy May 19, 2021
ba5cab5
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 3, 2021
0408cd5
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 7, 2021
7d5ede3
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 8, 2021
5dd3c98
Update Essentials/src/main/java/com/earth2me/essentials/User.java
JRoy Jun 10, 2021
819b1e8
Update Essentials/src/main/java/com/earth2me/essentials/IUser.java
JRoy Jun 10, 2021
1fb6653
Update Essentials/src/main/java/com/earth2me/essentials/IUser.java
JRoy Jun 10, 2021
7efc535
Update Essentials/src/main/java/com/earth2me/essentials/IUser.java
JRoy Jun 10, 2021
7d305e5
Update Essentials/src/main/java/com/earth2me/essentials/IUser.java
JRoy Jun 10, 2021
9788eef
Split up command usages
JRoy Jun 11, 2021
a6b9b8b
Rename a few method/param names
JRoy Jun 11, 2021
96299f1
Add Nullable annotation to getOutstandingTpaRequest
JRoy Jun 11, 2021
48cf2f5
Use TimeUnit for second to millisecond conversion
JRoy Jun 11, 2021
69501aa
Whitespace lulw
JRoy Jun 11, 2021
8094a26
Move wildcard check to equals
JRoy Jun 11, 2021
c2befcf
Fix variable name
JRoy Jun 11, 2021
7ed3ad6
wtf is a token
JRoy Jun 11, 2021
204bceb
Change in doc
JRoy Jun 11, 2021
0e31f6b
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 11, 2021
7706db1
Add TeleportRequestAcceptEvent
JRoy Jun 11, 2021
6c48eda
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 12, 2021
26b541f
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 14, 2021
22e2ea1
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 26, 2021
020a272
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 27, 2021
35a9737
Apply suggestions from code review
JRoy Jun 27, 2021
77185eb
wtf is a token
JRoy Jun 27, 2021
b3939f0
Clarify debug message
JRoy Jun 27, 2021
c0ce527
Javadocs go over annotations pinapl
JRoy Jun 27, 2021
1ed3d89
Rename event + cover denials
JRoy Jun 27, 2021
dc64a16
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 27, 2021
1d7b8b3
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jun 30, 2021
f877726
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 1, 2021
3e4b89c
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 1, 2021
5a93536
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 3, 2021
23e7345
pop_review.ogg
JRoy Jul 6, 2021
e4744af
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 6, 2021
5226e03
Review comments
JRoy Jul 10, 2021
f669867
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 10, 2021
77ac17d
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 10, 2021
66478f6
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 11, 2021
4713c0b
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 24, 2021
7d416ff
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 28, 2021
8842e88
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 29, 2021
bfd5e5f
Merge branch '2.x' into feature/tp-accept-queue
JRoy Jul 31, 2021
95dea76
Merge branch '2.x' into feature/tp-accept-queue
JRoy Aug 8, 2021
22ab4a7
Merge branch '2.x' into feature/tp-accept-queue
JRoy Aug 10, 2021
af146e2
Merge branch '2.x' into feature/tp-accept-queue
JRoy Aug 10, 2021
ca6838a
Merge branch '2.x' into feature/tp-accept-queue
JRoy Aug 24, 2021
2a9d617
Merge branch '2.x' into feature/tp-accept-queue
JRoy Aug 25, 2021
cc24e08
Merge branch '2.x' into feature/tp-accept-queue
mdcfe Aug 29, 2021
25085f5
Thanks triagonal
mdcfe Aug 29, 2021
f433f96
Merge branch '2.x' into feature/tp-accept-queue
JRoy Sep 7, 2021
842b324
Merge branch '2.x' into feature/tp-accept-queue
JRoy Sep 8, 2021
cb4153f
Merge branch '2.x' into feature/tp-accept-queue
JRoy Sep 15, 2021
1274af4
Merge branch '2.x' into feature/tp-accept-queue
JRoy Oct 8, 2021
eeafa10
Merge branch '2.x' into feature/tp-accept-queue
JRoy Oct 13, 2021
900d3e5
Merge branch '2.x' into feature/tp-accept-queue
JRoy Oct 20, 2021
d7d5d0c
Merge branch '2.x' into feature/tp-accept-queue
JRoy Oct 30, 2021
fac52b8
Merge branch '2.x' into feature/tp-accept-queue
JRoy Nov 6, 2021
5038c89
Merge branch '2.x' into feature/tp-accept-queue
JRoy Nov 20, 2021
bebb60e
Reduce duplicated code + improve variable names
JRoy Nov 20, 2021
5d9b5ff
Merge branch '2.x' into feature/tp-accept-queue
JRoy Nov 24, 2021
964757a
Merge branch '2.x' into feature/tp-accept-queue
JRoy Nov 25, 2021
5a1e017
Merge branch '2.x' into feature/tp-accept-queue
JRoy Nov 30, 2021
9cf87c3
Merge branch '2.x' into feature/tp-accept-queue
mdcfe Dec 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ public interface ISettings extends IConf {

long getTpaAcceptCancellation();

int getTpaMaxRequests();

long getTeleportInvulnerability();

boolean isTeleportInvulnerability();
Expand Down
83 changes: 83 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/IUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.math.BigDecimal;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -61,8 +64,11 @@ public interface IUser {
/**
* Returns whether this user has an outstanding teleport request to deal with.
*
* @deprecated The teleport request system has been moved into a multi-user teleport request queue.
* @see IUser#hasPendingTpaRequests(boolean, boolean)
* @return whether there is a teleport request
*/
@Deprecated
boolean hasOutstandingTeleportRequest();
JRoy marked this conversation as resolved.
Show resolved Hide resolved

/**
Expand Down Expand Up @@ -98,6 +104,11 @@ public interface IUser {

boolean canBuild();

/**
* @deprecated The teleport request system has been moved into a multi-user teleport request queue.
* @see IUser#getNextTpaRequest(boolean, boolean, boolean)
*/
@Deprecated
long getTeleportRequestTime();
JRoy marked this conversation as resolved.
Show resolved Hide resolved

void enableInvulnerabilityAfterTeleport();
Expand Down Expand Up @@ -205,6 +216,8 @@ public interface IUser {

String getName();

UUID getUUID();

String getDisplayName();

String getFormattedNickname();
Expand Down Expand Up @@ -238,4 +251,74 @@ public interface IUser {
void setToggleShout(boolean toggleShout);

boolean isToggleShout();

/**
* Gets information about the most-recently-made, non-expired TPA request in the tpa queue of this {@link IUser}.
* <p>
* The TPA Queue is Last-In-First-Out queue which stores all the active pending teleport
* requests of this {@link IUser}. Timeout calculations are also done during the
* iteration process of this method, ensuring that teleport requests made past the timeout
* period are removed from queue and therefore not returned here. The maximum size of this
* queue is determined by {@link ISettings#getTpaMaxRequests()}.
*
* @param inform true if the underlying {@link IUser} should be informed if a request expires during iteration.
* @param performExpirations true if this method should not spend time validating time for all items in the queue and just return the first item in the queue.
* @param excludeHere true if /tphere requests should be ignored in fetching the next tpa request.
* @return A {@link TpaRequest} corresponding to the next available request or null if no valid request is present.
*/
@Nullable TpaRequest getNextTpaRequest(boolean inform, boolean performExpirations, boolean excludeHere);

/**
* Whether or not this {@link IUser} has any valid TPA requests in queue.
*
* @param inform true if the user should be informed if a request expires during iteration.
* @param excludeHere true if /tpahere requests should be ignored in checking if a tpa request is available.
* @return true if the user has an available pending request in queue.
*/
boolean hasPendingTpaRequests(boolean inform, boolean excludeHere);

class TpaRequest {
private final String name;
JRoy marked this conversation as resolved.
Show resolved Hide resolved
private final UUID requesterUuid;
private boolean here;
private Location location;
private long time;

public TpaRequest(String name, UUID requesterUuid) {
this.name = name;
this.requesterUuid = requesterUuid;
}

public String getName() {
return name;
}

public UUID getRequesterUuid() {
return requesterUuid;
}

public boolean isHere() {
return here;
}

public void setHere(boolean here) {
this.here = here;
}

public Location getLocation() {
return location;
}

public void setLocation(Location location) {
this.location = location;
}

public long getTime() {
return time;
}

public void setTime(long time) {
this.time = time;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,11 @@ public long getTpaAcceptCancellation() {
return config.getLong("tpa-accept-cancellation", 120);
}

@Override
public int getTpaMaxRequests() {
return config.getInt("tpa-max-requests", 5);
}

private long _getTeleportInvulnerability() {
return config.getLong("teleport-invulnerability", 0) * 1000;
}
Expand Down
147 changes: 107 additions & 40 deletions Essentials/src/main/java/com/earth2me/essentials/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,21 @@
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -48,28 +53,37 @@
public class User extends UserData implements Comparable<User>, IMessageRecipient, net.ess3.api.IUser {
private static final Statistic PLAY_ONE_TICK = EnumUtil.getStatistic("PLAY_ONE_MINUTE", "PLAY_ONE_TICK");
private static final Logger logger = Logger.getLogger("Essentials");

// User modules
private final IMessageRecipient messageRecipient;
private transient final AsyncTeleport teleport;
private transient final Teleport legacyTeleport;

// User command confirmation strings
private final Map<User, BigDecimal> confirmingPayments = new WeakHashMap<>();
private transient UUID teleportRequester;
private transient boolean teleportRequestHere;
private transient Location teleportLocation;

// User teleport variables
private final transient LinkedHashMap<String, TpaRequest> teleportRequestQueue = new LinkedHashMap<>();

// User properties
private transient boolean vanished;
private transient long teleportRequestTime;
private transient long lastOnlineActivity;
private transient long lastThrottledAction;
private transient long lastActivity = System.currentTimeMillis();
private boolean hidden = false;
private boolean rightClickJump = false;
private transient Location afkPosition = null;
private boolean invSee = false;
private boolean recipeSee = false;
private boolean enderSee = false;
private transient long teleportInvulnerabilityTimestamp = 0;
private boolean ignoreMsg = false;

// User afk variables
private String afkMessage;
private long afkSince;
private transient Location afkPosition = null;

// Misc
private transient long lastOnlineActivity;
private transient long lastThrottledAction;
private transient long lastActivity = System.currentTimeMillis();
private transient long teleportInvulnerabilityTimestamp = 0;
private String confirmingClearCommand;
private long lastNotifiedAboutMailsMs;
private String lastHomeConfirmation;
Expand All @@ -90,9 +104,8 @@ public User(final Player base, final IEssentials ess) {
this.messageRecipient = new SimpleMessageRecipient(ess, this);
}

User update(final Player base) {
void update(final Player base) {
setBase(base);
return this;
}
JRoy marked this conversation as resolved.
Show resolved Hide resolved

@Override
Expand Down Expand Up @@ -327,44 +340,95 @@ public void setLogoutLocation() {

@Override
public void requestTeleport(final User player, final boolean here) {
teleportRequestTime = System.currentTimeMillis();
teleportRequester = player == null ? null : player.getBase().getUniqueId();
teleportRequestHere = here;
if (player == null) {
teleportLocation = null;
} else {
teleportLocation = here ? player.getLocation() : this.getLocation();
final TpaRequest request = teleportRequestQueue.getOrDefault(player.getName(), new TpaRequest(player.getName(), player.getUUID()));
request.setTime(System.currentTimeMillis());
request.setHere(here);
request.setLocation(here ? player.getLocation() : this.getLocation());

// Handle max queue size
teleportRequestQueue.remove(request.getName());
if (teleportRequestQueue.size() >= ess.getSettings().getTpaMaxRequests()) {
String lastKey = null;
for (Map.Entry<String, TpaRequest> entry : teleportRequestQueue.entrySet()) {
lastKey = entry.getKey();
}
teleportRequestQueue.remove(lastKey);
}

// Add request to queue
teleportRequestQueue.put(request.getName(), request);
}

@Override
@Deprecated
public boolean hasOutstandingTeleportRequest() {
if (getTeleportRequest() != null) { // Player has outstanding teleport request.
final long timeout = ess.getSettings().getTpaAcceptCancellation();
if (timeout != 0) {
if ((System.currentTimeMillis() - getTeleportRequestTime()) / 1000 <= timeout) { // Player has outstanding request
return true;
} else { // outstanding request expired.
requestTeleport(null, false);
return false;
}
} else { // outstanding request does not expire
return true;
}
}
return false;
return getNextTpaRequest(false, false, false) != null;
}

public Collection<String> getPendingTpaKeys() {
return teleportRequestQueue.keySet();
}

public UUID getTeleportRequest() {
return teleportRequester;
@Override
public boolean hasPendingTpaRequests(boolean inform, boolean excludeHere) {
return getNextTpaRequest(inform, false, excludeHere) != null;
}

public boolean hasOutstandingTpaRequest(String playerUsername, boolean here) {
final TpaRequest request = getOutstandingTpaRequest(playerUsername, false);
return request != null && request.isHere() == here;
}

public @Nullable TpaRequest getOutstandingTpaRequest(String playerUsername, boolean inform) {
if (!teleportRequestQueue.containsKey(playerUsername)) {
return null;
}

final long timeout = ess.getSettings().getTpaAcceptCancellation();
final TpaRequest request = teleportRequestQueue.get(playerUsername);
if (timeout < 1 || System.currentTimeMillis() - request.getTime() <= timeout * 1000) {
return request;
}
teleportRequestQueue.remove(playerUsername);
if (inform) {
sendMessage(tl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName()));
}
return null;
}

public boolean isTpRequestHere() {
return teleportRequestHere;
public TpaRequest removeTpaRequest(String playerUsername) {
return teleportRequestQueue.remove(playerUsername);
}

public Location getTpRequestLocation() {
return teleportLocation;
@Override
public TpaRequest getNextTpaRequest(boolean inform, boolean performExpirations, boolean excludeHere) {
if (teleportRequestQueue.isEmpty()) {
return null;
}

final long timeout = ess.getSettings().getTpaAcceptCancellation();
final Iterator<Map.Entry<String, TpaRequest>> iterator = teleportRequestQueue.entrySet().iterator();
TpaRequest nextRequest = null;
while (iterator.hasNext()) {
JRoy marked this conversation as resolved.
Show resolved Hide resolved
final TpaRequest request = iterator.next().getValue();
if (timeout < 1 || (System.currentTimeMillis() - request.getTime()) <= TimeUnit.SECONDS.toMillis(timeout)) {
if (excludeHere && request.isHere()) {
continue;
}

if (performExpirations) {
return request;
} else if (nextRequest == null) {
nextRequest = request;
}
} else {
if (inform) {
sendMessage(tl("requestTimedOutFrom", ess.getUser(request.getRequesterUuid()).getDisplayName()));
}
iterator.remove();
}
}
return nextRequest;
}

public String getNick() {
Expand Down Expand Up @@ -823,8 +887,11 @@ public boolean canBuild() {
return ess.getPermissionsHandler().canBuild(base, getGroup());
}

@Override
@Deprecated
public long getTeleportRequestTime() {
return teleportRequestTime;
final TpaRequest request = getNextTpaRequest(false, false, false);
return request == null ? 0L : request.getTime();
}

public boolean isInvSee() {
Expand Down Expand Up @@ -990,7 +1057,7 @@ public String getName() {

@Override
public UUID getUUID() {
return getBase().getUniqueId();
return this.getBase().getUniqueId();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ public void run(final Server server, final User user, final String commandLabel,
if (user.getWorld() != player.getWorld() && ess.getSettings().isWorldTeleportPermissions() && !user.isAuthorized("essentials.worlds." + player.getWorld().getName())) {
throw new Exception(tl("noPerm", "essentials.worlds." + player.getWorld().getName()));
}

// Don't let sender request teleport twice to the same player.
if (user.getConfigUUID().equals(player.getTeleportRequest()) && player.hasOutstandingTeleportRequest() // Check timeout
&& !player.isTpRequestHere()) { // Make sure the last teleport request was actually tpa and not tpahere
if (player.hasOutstandingTpaRequest(user.getName(), false)) {
throw new Exception(tl("requestSentAlready", player.getDisplayName()));
}

if (player.isAutoTeleportEnabled() && !player.isIgnoredPlayer(user)) {
final Trade charge = new Trade(this.getName(), ess);
final AsyncTeleport teleport = user.getAsyncTeleport();
Expand Down Expand Up @@ -71,6 +72,7 @@ public void run(final Server server, final User user, final String commandLabel,
player.sendMessage(tl("teleportRequestTimeoutInfo", ess.getSettings().getTpaAcceptCancellation()));
}
}

user.sendMessage(tl("requestSent", player.getDisplayName()));
if (user.isAuthorized("essentials.tpacancel")) {
user.sendMessage(tl("typeTpacancel"));
Expand Down
Loading