mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-22 02:35:21 +01:00
commit
97d42e4151
9
pom.xml
9
pom.xml
@ -88,7 +88,7 @@
|
||||
<!-- Do not change unless you want different name for local builds. -->
|
||||
<build.number>-LOCAL</build.number>
|
||||
<!-- This allows to change between versions. -->
|
||||
<build.version>2.5.2</build.version>
|
||||
<build.version>2.5.3</build.version>
|
||||
<sonar.organization>bentobox-world</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
<server.jars>${project.basedir}/lib</server.jars>
|
||||
@ -228,6 +228,13 @@
|
||||
<version>3.11.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- For test that need a time to test -->
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>4.2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
|
@ -324,6 +324,8 @@ public class BentoBox extends JavaPlugin implements Listener {
|
||||
// Stop all async database tasks
|
||||
shutdown = true;
|
||||
|
||||
HeadGetter.shutdown();
|
||||
|
||||
if (addonsManager != null) {
|
||||
addonsManager.disableAddons();
|
||||
}
|
||||
|
@ -140,17 +140,30 @@ public class IslandTeamCommand extends CompositeCommand {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player has been invited
|
||||
* Check if a player has been invited - validates any invite that may be in the system
|
||||
* @param invitee - UUID of invitee to check
|
||||
* @return true if invited, false if not
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public boolean isInvited(@NonNull UUID invitee) {
|
||||
return handler.objectExists(invitee.toString());
|
||||
boolean valid = false;
|
||||
if (handler.objectExists(invitee.toString())) {
|
||||
@Nullable
|
||||
TeamInvite invite = getInvite(invitee);
|
||||
valid = getIslands().getIslandById(invite.getUniqueId()).map(island -> island.isOwned() // Still owned by someone
|
||||
&& !island.isDeleted() // Not deleted
|
||||
&& island.getMemberSet().contains(invite.getInviter()) // the inviter is still a member of the island
|
||||
).orElse(false);
|
||||
if (!valid) {
|
||||
// Remove invite
|
||||
handler.deleteObject(invite);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whoever invited invitee
|
||||
* Get whoever invited invitee.
|
||||
* @param invitee - uuid
|
||||
* @return UUID of inviter, or null if invitee has not been invited
|
||||
* @since 1.8.0
|
||||
|
@ -48,6 +48,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
||||
UUID prospectiveOwnerUUID = itc.getInviter(playerUUID);
|
||||
if (prospectiveOwnerUUID == null) {
|
||||
user.sendMessage(INVALID_INVITE);
|
||||
itc.removeInvite(playerUUID);
|
||||
return false;
|
||||
}
|
||||
TeamInvite invite = itc.getInvite(playerUUID);
|
||||
@ -65,6 +66,7 @@ public class IslandTeamInviteAcceptCommand extends ConfirmableCommand {
|
||||
if (getIWM().getWorldSettings(getWorld()).isDisallowTeamMemberIslands()
|
||||
&& getIslands().inTeam(getWorld(), playerUUID)) {
|
||||
user.sendMessage("commands.island.team.invite.errors.you-already-are-in-team");
|
||||
itc.removeInvite(playerUUID);
|
||||
return false;
|
||||
}
|
||||
// Fire event so add-ons can run commands, etc.
|
||||
|
@ -61,7 +61,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
|
||||
if (args.size() != 1) {
|
||||
new IslandTeamInviteGUI(itc, true, island).build(user);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int rank = Objects.requireNonNull(island).getRank(user);
|
||||
@ -153,6 +153,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
Island island = getIslands().getIsland(getWorld(), user.getUniqueId());
|
||||
if (island == null) {
|
||||
user.sendMessage("general.errors.no-island");
|
||||
invitedPlayer = null;
|
||||
return false;
|
||||
}
|
||||
// Fire event so add-ons can run commands, etc.
|
||||
@ -162,6 +163,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
.involvedPlayer(invitedPlayer.getUniqueId())
|
||||
.build();
|
||||
if (e.getNewEvent().map(IslandBaseEvent::isCancelled).orElse(e.isCancelled())) {
|
||||
invitedPlayer = null;
|
||||
return false;
|
||||
}
|
||||
// Put the invited player (key) onto the list with inviter (value)
|
||||
@ -175,6 +177,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
&& getIslands().hasIsland(getWorld(), invitedPlayer.getUniqueId())) {
|
||||
invitedPlayer.sendMessage("commands.island.team.invite.you-will-lose-your-island");
|
||||
}
|
||||
invitedPlayer = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -505,12 +505,6 @@ public class User implements MetaDataAble {
|
||||
private String replacePrefixes(String translation, String[] variables) {
|
||||
for (String prefix : plugin.getLocalesManager().getAvailablePrefixes(this)) {
|
||||
String prefixTranslation = getTranslation("prefixes." + prefix);
|
||||
// Replace the [gamemode] text variable
|
||||
prefixTranslation = prefixTranslation.replace("[gamemode]",
|
||||
addon != null ? addon.getDescription().getName() : "[gamemode]");
|
||||
// Replace the [friendly_name] text variable
|
||||
prefixTranslation = prefixTranslation.replace("[friendly_name]",
|
||||
isPlayer() ? plugin.getIWM().getFriendlyName(getWorld()) : "[friendly_name]");
|
||||
|
||||
// Replace the prefix in the actual message
|
||||
translation = translation.replace("[prefix_" + prefix + "]", prefixTranslation);
|
||||
@ -530,6 +524,17 @@ public class User implements MetaDataAble {
|
||||
if (player != null) {
|
||||
translation = plugin.getPlaceholdersManager().replacePlaceholders(player, translation);
|
||||
}
|
||||
|
||||
// Replace game mode and friendly name in general
|
||||
// Replace the [gamemode] text variable
|
||||
if (addon != null && addon.getDescription() != null) {
|
||||
translation = translation.replace("[gamemode]", addon.getDescription().getName());
|
||||
}
|
||||
if (player != null && player.getWorld() != null) {
|
||||
// Replace the [friendly_name] text variable
|
||||
translation = translation.replace("[friendly_name]",
|
||||
isPlayer() ? plugin.getIWM().getFriendlyName(getWorld()) : "[friendly_name]");
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,6 @@ import org.bukkit.event.vehicle.VehicleDamageEvent;
|
||||
|
||||
import com.google.common.base.Enums;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.flags.FlagListener;
|
||||
import world.bentobox.bentobox.lists.Flags;
|
||||
|
||||
@ -51,6 +50,7 @@ public class BreakBlocksListener extends FlagListener {
|
||||
|| m == Material.SWEET_BERRY_BUSH
|
||||
|| m == Material.BAMBOO
|
||||
|| m == Material.NETHER_WART
|
||||
|| m == Material.CACTUS
|
||||
) {
|
||||
this.checkIsland(e, p, l, Flags.HARVEST);
|
||||
} else {
|
||||
|
@ -80,7 +80,7 @@ public class EntityInteractListener extends FlagListener {
|
||||
this.checkIsland(e, p, l, Flags.BOAT);
|
||||
}
|
||||
}
|
||||
else if (e.getRightClicked() instanceof Villager || e.getRightClicked() instanceof WanderingTrader)
|
||||
else if (e.getRightClicked() instanceof Villager && !(e.getRightClicked() instanceof WanderingTrader))
|
||||
{
|
||||
// Villager trading
|
||||
// Check naming and check trading
|
||||
|
@ -1209,6 +1209,7 @@ public class IslandsManager {
|
||||
*/
|
||||
public void setSpawn(@NonNull Island spawn) {
|
||||
if (spawn.getWorld() != null) {
|
||||
spawn.setSpawn(true);
|
||||
spawns.put(Util.getWorld(spawn.getWorld()), spawn);
|
||||
// Tell other servers
|
||||
MultiLib.notify("bentobox-setspawn", spawn.getWorld().getUID().toString() + "," + spawn.getUniqueId());
|
||||
@ -1223,9 +1224,12 @@ public class IslandsManager {
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public void clearSpawn(World world) {
|
||||
spawns.remove(world);
|
||||
// Tell other servers
|
||||
MultiLib.notify("bentobox-setspawn", world.getUID().toString());
|
||||
if (spawns.containsKey(world)) {
|
||||
spawns.get(world).setSpawn(false);
|
||||
spawns.remove(world);
|
||||
// Tell other servers
|
||||
MultiLib.notify("bentobox-setspawn", world.getUID().toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,12 +4,11 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -23,6 +22,7 @@ import world.bentobox.bentobox.database.Database;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.database.objects.Names;
|
||||
import world.bentobox.bentobox.database.objects.Players;
|
||||
import world.bentobox.bentobox.util.ExpiringMap;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
public class PlayersManager {
|
||||
@ -30,7 +30,7 @@ public class PlayersManager {
|
||||
private final BentoBox plugin;
|
||||
private Database<Players> handler;
|
||||
private final Database<Names> names;
|
||||
private final Map<UUID, Players> playerCache = new ConcurrentHashMap<>();
|
||||
private final ExpiringMap<UUID, Players> playerCache = new ExpiringMap<>(2, TimeUnit.HOURS);
|
||||
private final @NonNull List<Names> nameCache;
|
||||
private final Set<UUID> inTeleport; // this needs databasing
|
||||
|
||||
@ -61,6 +61,7 @@ public class PlayersManager {
|
||||
|
||||
public void shutdown(){
|
||||
handler.close();
|
||||
playerCache.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
271
src/main/java/world/bentobox/bentobox/util/ExpiringMap.java
Normal file
271
src/main/java/world/bentobox/bentobox/util/ExpiringMap.java
Normal file
@ -0,0 +1,271 @@
|
||||
package world.bentobox.bentobox.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A {@code ExpiringMap} is a map implementation that automatically removes entries after a
|
||||
* specified period of time. The expiration time is specified when the map is created and
|
||||
* applies to all entries put into the map. It is thread-safe and provides similar
|
||||
* functionality to {@code HashMap} with the added feature of automatic expiration of entries.
|
||||
*
|
||||
* <p>This class makes use of a {@link ConcurrentHashMap} for thread safety and a
|
||||
* {@link ScheduledExecutorService} to handle the expiration of entries. All operations are
|
||||
* thread-safe.
|
||||
*
|
||||
* @param <K> the type of keys maintained by this map
|
||||
* @param <V> the type of mapped values
|
||||
*/
|
||||
public class ExpiringMap<K, V> implements Map<K, V> {
|
||||
private final Map<K, V> map;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final long expirationTime;
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code ExpiringMap} with the specified expiration time for entries.
|
||||
*
|
||||
* @param expirationTime the time after which entries should expire, in the specified time unit
|
||||
* @param timeUnit the time unit for the {@code expirationTime} parameter
|
||||
* @throws IllegalArgumentException if {@code expirationTime} is less than or equal to zero
|
||||
* @throws NullPointerException if {@code timeUnit} is null
|
||||
*/
|
||||
public ExpiringMap(long expirationTime, TimeUnit timeUnit) {
|
||||
if (expirationTime <= 0) {
|
||||
throw new IllegalArgumentException("Expiration time must be greater than zero.");
|
||||
}
|
||||
if (timeUnit == null) {
|
||||
throw new NullPointerException("TimeUnit cannot be null.");
|
||||
}
|
||||
this.map = new ConcurrentHashMap<>();
|
||||
this.scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
this.expirationTime = timeUnit.toMillis(expirationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the specified value with the specified key in this map. If the map
|
||||
* previously contained a mapping for the key, the old value is replaced.
|
||||
* The entry will automatically be removed after the specified expiration time.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param value value to be associated with the specified key
|
||||
* @throws NullPointerException if the specified key or value is null
|
||||
* @return the previous value associated with {@code key}, or {@code null} if there was no mapping for {@code key}.
|
||||
*/
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if (key == null || value == null) {
|
||||
throw new NullPointerException("Key and Value cannot be null.");
|
||||
}
|
||||
V oldValue = map.put(key, value);
|
||||
scheduleRemoval(key);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified key is mapped, or {@code null} if this map contains
|
||||
* no mapping for the key.
|
||||
*
|
||||
* @param key the key whose associated value is to be returned
|
||||
* @return the value to which the specified key is mapped, or {@code null} if this map contains no mapping for the key
|
||||
* @throws NullPointerException if the specified key is null
|
||||
*/
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("Key cannot be null.");
|
||||
}
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping for a key from this map if it is present.
|
||||
*
|
||||
* @param key key whose mapping is to be removed from the map
|
||||
* @return the previous value associated with {@code key}, or {@code null} if there was no mapping for {@code key}.
|
||||
* (A {@code null} return can also indicate that the map previously associated {@code null} with {@code key}.)
|
||||
* @throws NullPointerException if the specified key is null
|
||||
*/
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("Key cannot be null.");
|
||||
}
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains a mapping for the specified key.
|
||||
*
|
||||
* @param key key whose presence in this map is to be tested
|
||||
* @return {@code true} if this map contains a mapping for the specified key
|
||||
* @throws NullPointerException if the specified key is null
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("Key cannot be null.");
|
||||
}
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map maps one or more keys to the specified value.
|
||||
*
|
||||
* @param value value whose presence in this map is to be tested
|
||||
* @return {@code true} if this map maps one or more keys to the specified value
|
||||
* @throws NullPointerException if the specified value is null
|
||||
*/
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("Value cannot be null.");
|
||||
}
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings in this map. If the map contains more than
|
||||
* {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}.
|
||||
*
|
||||
* @return the number of key-value mappings in this map
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this map contains no key-value mappings.
|
||||
*
|
||||
* @return {@code true} if this map contains no key-value mappings
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all of the mappings from the specified map to this map. The effect of this call is
|
||||
* equivalent to that of calling {@link #put(Object, Object) put(k, v)} on this map once
|
||||
* for each mapping from key {@code k} to value {@code v} in the specified map. The behavior
|
||||
* of this operation is undefined if the specified map is modified while the operation is in progress.
|
||||
*
|
||||
* @param m mappings to be stored in this map
|
||||
* @throws NullPointerException if the specified map is null, or if any key or value in the specified map is null
|
||||
*/
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
if (m == null) {
|
||||
throw new NullPointerException("The specified map cannot be null.");
|
||||
}
|
||||
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the mappings from this map. The map will be empty after this call returns.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} view of the keys contained in this map. The set is backed by the map,
|
||||
* so changes to the map are reflected in the set, and vice-versa. If the map is modified while
|
||||
* an iteration over the set is in progress, the results of the iteration are undefined. The set
|
||||
* supports element removal, which removes the corresponding mapping from the map, via the
|
||||
* {@code Iterator.remove}, {@code Set.remove}, {@code removeAll}, {@code retainAll}, and
|
||||
* {@code clear} operations. It does not support the {@code add} or {@code addAll} operations.
|
||||
*
|
||||
* @return a set view of the keys contained in this map
|
||||
*/
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} view of the values contained in this map. The collection is
|
||||
* backed by the map, so changes to the map are reflected in the collection, and vice-versa.
|
||||
* If the map is modified while an iteration over the collection is in progress, the results
|
||||
* of the iteration are undefined. The collection supports element removal, which removes
|
||||
* the corresponding mapping from the map, via the {@code Iterator.remove}, {@code Collection.remove},
|
||||
* {@code removeAll}, {@code retainAll}, and {@code clear} operations. It does not support the
|
||||
* {@code add} or {@code addAll} operations.
|
||||
*
|
||||
* @return a collection view of the values contained in this map
|
||||
*/
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Set} view of the mappings contained in this map. The set is backed by the map,
|
||||
* so changes to the map are reflected in the set, and vice-versa. If the map is modified while
|
||||
* an iteration over the set is in progress, the results of the iteration are undefined. The set
|
||||
* supports element removal, which removes the corresponding mapping from the map, via the
|
||||
* {@code Iterator.remove}, {@code Set.remove}, {@code removeAll}, {@code retainAll}, and
|
||||
* {@code clear} operations. It does not support the {@code add} or {@code addAll} operations.
|
||||
*
|
||||
* @return a set view of the mappings contained in this map
|
||||
*/
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the specified key is not already associated with a value, attempts to compute its
|
||||
* value using the given mapping function and enters it into this map unless {@code null}.
|
||||
*
|
||||
* <p>If the mapping function returns {@code null}, no mapping is recorded. If the mapping
|
||||
* function itself throws an (unchecked) exception, the exception is rethrown, and no mapping
|
||||
* is recorded. The computed value is set to expire after the specified expiration time.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param mappingFunction the function to compute a value
|
||||
* @return the current (existing or computed) value associated with the specified key, or {@code null} if the computed value is {@code null}
|
||||
* @throws NullPointerException if the specified key or mappingFunction is null
|
||||
*/
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
if (key == null || mappingFunction == null) {
|
||||
throw new NullPointerException("Key and mappingFunction cannot be null.");
|
||||
}
|
||||
return map.computeIfAbsent(key, k -> {
|
||||
V value = mappingFunction.apply(k);
|
||||
scheduleRemoval(k);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the removal of the specified key from this map after the expiration time.
|
||||
*
|
||||
* @param key key whose mapping is to be removed from the map after the expiration time
|
||||
*/
|
||||
private void scheduleRemoval(final K key) {
|
||||
scheduler.schedule(() -> map.remove(key), expirationTime, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the {@code ScheduledExecutorService} used for scheduling the removal of
|
||||
* entries. This method should be called to release resources once the {@code ExpiringMap}
|
||||
* is no longer needed.
|
||||
*
|
||||
* <p>Once the executor is shut down, no more entries will be automatically removed.
|
||||
* It is the user's responsibility to ensure that the {@code shutdown} method is called.
|
||||
*/
|
||||
public void shutdown() {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
}
|
@ -5,13 +5,12 @@ import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -25,6 +24,7 @@ import com.google.gson.JsonObject;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.util.ExpiringMap;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
|
||||
/**
|
||||
@ -36,7 +36,7 @@ public class HeadGetter {
|
||||
/**
|
||||
* Local cache for storing player heads.
|
||||
*/
|
||||
private static final Map<String, HeadCache> cachedHeads = new HashMap<>();
|
||||
private static final ExpiringMap<String, HeadCache> cachedHeads = new ExpiringMap<>(1, TimeUnit.HOURS);
|
||||
|
||||
/**
|
||||
* Local cache for storing requested names and items which must be updated.
|
||||
@ -46,7 +46,8 @@ public class HeadGetter {
|
||||
/**
|
||||
* Requesters of player heads.
|
||||
*/
|
||||
private static final Map<String, Set<HeadRequester>> headRequesters = new HashMap<>();
|
||||
private static final ExpiringMap<String, Set<HeadRequester>> headRequesters = new ExpiringMap<>(10,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
private static final String TEXTURES = "textures";
|
||||
|
||||
@ -65,6 +66,14 @@ public class HeadGetter {
|
||||
this.runPlayerHeadGetter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the schedulers
|
||||
*/
|
||||
public static void shutdown() {
|
||||
cachedHeads.shutdown();
|
||||
headRequesters.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param panelItem - head to update
|
||||
* @param requester - callback class
|
||||
|
@ -138,7 +138,13 @@ commands:
|
||||
parameters: "<player>"
|
||||
description: überträgt das Insel-Eigentum auf den Spieler
|
||||
already-owner: "&c [name] ist bereits der Besitzer dieser Insel!"
|
||||
must-be-on-island: "&c Sie müssen auf der Insel sein, um den Besitzer festzulegen"
|
||||
confirmation: "&a Möchten Sie [name] wirklich als Eigentümer der Insel in
|
||||
[xyz] festlegen?"
|
||||
success: "&b [name]&a ist jetzt der Besitzer dieser Insel."
|
||||
extra-islands: "&c Warnung: Dieser Spieler besitzt jetzt [number] Inseln.
|
||||
Das sind mehr als durch die Einstellungen oder Berechtigungen erlaubt ist:
|
||||
[max]."
|
||||
range:
|
||||
description: Admin Insel Bereichsbefehl
|
||||
invalid-value:
|
||||
@ -158,7 +164,7 @@ commands:
|
||||
Grüne Partikel &f zeigen den voreingestellten Schutzbereich an, wenn der Inselschutzbereich davon abweicht.
|
||||
showing: "&2 Anzeigen von Reichweite Indikatoren"
|
||||
set:
|
||||
parameters: "<player> <range>"
|
||||
parameters: "<Spieler> <Reichweite> [Inselstandort]"
|
||||
description: legt den geschützten Inselbereich fest
|
||||
success: "&a Inselschutzbereich einstellen auf &b [number]&a ."
|
||||
reset:
|
||||
@ -167,12 +173,12 @@ commands:
|
||||
success: "& a Setzen Sie den Inselschutzbereich auf & b [number] & a zurück."
|
||||
add:
|
||||
description: Erhöht den Schutzbereich der Insel
|
||||
parameters: "<player> <range>"
|
||||
parameters: "<Spieler> <Reichweite> [Inselstandort]"
|
||||
success: "&a Erfolgreiche Erhöhung von &b [name]&a 's geschützten Bereich
|
||||
der Insel auf &b [total] &7 (&b +[number]&7 )&a ."
|
||||
remove:
|
||||
description: Verringert den Schutzbereich der Insel
|
||||
parameters: "<player> <range>"
|
||||
parameters: "<Spieler> <Reichweite> [Inselstandort]"
|
||||
success: "&a Erfolgreich reduziert &b [name]&a 's geschützten Bereich der
|
||||
Insel auf&b [total] &7 (&b -[number]&7 )&a ."
|
||||
register:
|
||||
@ -191,6 +197,11 @@ commands:
|
||||
parameters: "<owner> [x,y,z]"
|
||||
description: Besitzer von Insel entfernen, aber Inselblöcke behalten
|
||||
unregistered-island: "&a Unregistrierter Spieler von der Insel bei [xyz]."
|
||||
errors:
|
||||
unknown-island-location: "&c Unbekannter Inselstandort"
|
||||
specify-island-location: "&c Gib denn Inselstandort in x,y,z Format an"
|
||||
player-has-more-than-one-island: "&c Spieler hat mehr als eine Insel. Gib
|
||||
an welche"
|
||||
info:
|
||||
parameters: "<player>"
|
||||
description: Informationen über deinen Standort oder die Spielerinsel erhalten
|
||||
@ -219,6 +230,7 @@ commands:
|
||||
banned-players: 'Gebannte Spieler:'
|
||||
banned-format: "&c [name]"
|
||||
unowned: "&c Frei"
|
||||
bundle: "&a Blaupausenpaket zum Erstellen der Insel: &b [name]"
|
||||
switch:
|
||||
description: Schutzumgehung ein-/ausschalten
|
||||
op: "&c Ops können den Schutz immer umgehen. Deop um den Befehl zu benutzen."
|
||||
@ -257,10 +269,13 @@ commands:
|
||||
reload:
|
||||
description: neu laden
|
||||
tp:
|
||||
parameters: "<player>"
|
||||
parameters: "<Spieler> [Insel des Spielers]"
|
||||
description: zu einer Spielerinsel teleportieren
|
||||
manual: "&c Kein sicherer Warp gefunden! Manuell in die Nähe von &b [location]
|
||||
&c teleportieren und nachsehen"
|
||||
tpuser:
|
||||
parameters: "<teleportierender Spieler> <Spieler der Insel> [Insel des Spielers]"
|
||||
description: einen Spieler zur Insel eines anderen Spielers teleportieren
|
||||
getrank:
|
||||
parameters: "<player>"
|
||||
description: den Rang eines Spielers auf seiner Insel erhalten
|
||||
@ -406,6 +421,12 @@ commands:
|
||||
slot-instructions: |-
|
||||
&a Linksklick zum Erhöhen
|
||||
&a Rechtsklick zum Verringern
|
||||
times: |
|
||||
&a Maximale gleichzeitige Nutzung durch Spieler
|
||||
&a Linksklick zum Erhöhen
|
||||
&a Rechtsklick zum Verringern
|
||||
unlimited-times: Unbegrenzt
|
||||
maximum-times: Max. [number] Mal
|
||||
resetflags:
|
||||
parameters: "[flag]"
|
||||
description: Alle Inseln in der config.yml auf Standard-Flag-Einstellungen zurücksetzen
|
||||
@ -498,6 +519,18 @@ commands:
|
||||
addons: "&6 Migrieren von Addons"
|
||||
class: "&6 Migration [description]"
|
||||
migrated: "&A migriert"
|
||||
completed: "[prefix_bentobox]&a Abgeschlossen"
|
||||
rank:
|
||||
description: Ränge auflisten, hinzufügen oder entfernen
|
||||
parameters: "&a [list | add | remove] [Rangreferenz] [Rangwert]"
|
||||
add:
|
||||
success: "&a [rank] mit Wert [number] hinzugefügt"
|
||||
failure: "&c [rank] konnte nicht mit dem Wert [number] hinzugefügt werden.
|
||||
Vielleicht ein Duplikat?"
|
||||
remove:
|
||||
success: "&a Entfernt [rank]"
|
||||
failure: "&c [rank] konnte nicht entfernt werden. Unbekannter Rang."
|
||||
list: "&a Die registrierten Ränge sind wie folgt:"
|
||||
confirmation:
|
||||
confirm: "&c Befehl innerhalb von &b [seconds]s&c zur Bestätigung erneut eingeben."
|
||||
previous-request-cancelled: "&6 Vorherige Bestätigungsanforderung abgebrochen."
|
||||
@ -533,6 +566,9 @@ commands:
|
||||
einen Admin."
|
||||
creating-island: "&a Einen Ort für deine Insel finden..."
|
||||
you-cannot-make: "&c Du kannst keine weiteren Inseln erschaffen!"
|
||||
max-uses: "&c Von dieser Art Inseln kann man keine weiteren machen!"
|
||||
you-cannot-make-team: "&c Teammitglieder können keine Inseln in derselben Welt
|
||||
wie ihre Teaminsel erstellen."
|
||||
pasting:
|
||||
estimated-time: "&a Geschätzte Zeit: &b [number] &a Sekunden."
|
||||
blocks: "&a Block für Block aufbauen: &b [number] &a Blöcke insgesamt..."
|
||||
@ -600,18 +636,53 @@ commands:
|
||||
description: einen Heimatort umbenennen
|
||||
parameters: "[Heimatname]"
|
||||
enter-new-name: "&6 Geben Sie den neuen Namen ein"
|
||||
already-exists: "&c Dieser Name existiert bereits, versuchen Sie es mit einem anderen Namen."
|
||||
already-exists: "&c Dieser Name existiert bereits, versuchen Sie es mit einem
|
||||
anderen Namen."
|
||||
resetname:
|
||||
description: setze deinen Inselnamen zurück
|
||||
success: "&a Setzen Sie Ihren Inselnamen erfolgreich zurück."
|
||||
team:
|
||||
description: Dein Team verwalten
|
||||
gui:
|
||||
titles:
|
||||
team-panel: Teammanagement
|
||||
buttons:
|
||||
status:
|
||||
name: Status
|
||||
description: Der Status des Teams
|
||||
rank-filter:
|
||||
name: Rangfilter
|
||||
description: "&a Klicken Sie hier, um die Ränge zu wechseln"
|
||||
invitation: Einladung
|
||||
invite:
|
||||
name: Spieler einladen
|
||||
description: |
|
||||
&a Spieler müssen sich in der
|
||||
&a selben Welt wie Sie befinden, um
|
||||
&a in der Liste angezeigt zu werden.
|
||||
tips:
|
||||
LEFT:
|
||||
name: "&b Linksklick"
|
||||
invite: "&a, um einen Spieler einzuladen"
|
||||
RIGHT:
|
||||
name: "&b Rechtsklick"
|
||||
SHIFT_RIGHT:
|
||||
name: "&b Umschalttaste Rechtsklick"
|
||||
reject: "&a zum Ablehnen"
|
||||
kick: "&a um Spieler rauszuwerfen"
|
||||
leave: "&a verlässt das Team"
|
||||
SHIFT_LEFT:
|
||||
name: "&b Umschalttaste Linksklick"
|
||||
accept: "&a zum Akzeptieren"
|
||||
setowner: |
|
||||
&a, um den Besitzer
|
||||
&a für diesen Spieler festzulegen
|
||||
info:
|
||||
description: zeigt detaillierte Informationen über dein Team an
|
||||
member-layout:
|
||||
online: '&a &l o &r &f [name]'
|
||||
offline: '&c &l o &r &f [name] &7 ([last_seen])'
|
||||
offline-not-last-seen: '&c &l o &r &f [name]'
|
||||
online: "&a &l o &r &f [name]"
|
||||
offline: "&c &l o &r &f [name] &7 ([last_seen])"
|
||||
offline-not-last-seen: "&c &l o &r &f [name]"
|
||||
last-seen:
|
||||
layout: "&b [number] &7 [unit] vorher"
|
||||
days: Tage
|
||||
@ -631,8 +702,10 @@ commands:
|
||||
already-has-rank: "&c Der Spieler hat bereits einen Rang!"
|
||||
you-are-a-coop-member: "&2 Du wurdest von [name] gecooped"
|
||||
success: "&a Du hast &b [name] gecooped."
|
||||
name-has-invited-you: "&a [name] hat dich eingeladen, ein Coop-Mitglied ihrer
|
||||
Insel zu werden."
|
||||
name-has-invited-you: |
|
||||
&a [name] hat Sie eingeladen,
|
||||
&a als Genossenschaftsmitglied
|
||||
&a ihrer Insel beizutreten.
|
||||
uncoop:
|
||||
description: einen Coop-Rang von einem Spieler entfernen
|
||||
parameters: "<player>"
|
||||
@ -649,8 +722,10 @@ commands:
|
||||
description: Gib einem Spieler einen vertrauenswürdigen Rang auf deiner Insel
|
||||
parameters: "<player>"
|
||||
trust-in-yourself: "&c Vertraue auf dich selbst!"
|
||||
name-has-invited-you: "&a [name] hat dich eingeladen, ein vertrauenswürdiges
|
||||
Mitglied ihrer Insel zu werden."
|
||||
name-has-invited-you: |
|
||||
&a [name] hat Sie eingeladen,
|
||||
&a als vertrauenswürdiges Mitglied
|
||||
&a ihrer Insel beizutreten.
|
||||
player-already-trusted: "&c Der Spieler ist bereits vertrauenswürdig!"
|
||||
you-are-trusted: "&2 Du bist vertrauenswürdig für &b [name]&a !"
|
||||
success: "&a Du vertraust &b [name]&a ."
|
||||
@ -668,11 +743,38 @@ commands:
|
||||
description: einen Spieler auf deine Insel einladen
|
||||
invitation-sent: "&a Einladung gesendet an [name]"
|
||||
removing-invite: "&c Einladung entfernen"
|
||||
name-has-invited-you: "&a [name] hat dich eingeladen ihrer Insel beizutreten."
|
||||
name-has-invited-you: |
|
||||
&a [name] hat Sie eingeladen,
|
||||
&a ihrer Insel beizutreten.
|
||||
to-accept-or-reject: "&a Gib /[label] team accept um zu akzeptieren, oder
|
||||
/[label] team reject um abzulehnen"
|
||||
you-will-lose-your-island: "&c WARNUNG! Du wirst deine Insel verlieren, wenn
|
||||
du akzeptierst!"
|
||||
you-will-lose-your-island: |
|
||||
&c WARNUNG! Sie verlieren alle
|
||||
&c Ihre Inseln, wenn Sie akzeptieren!
|
||||
gui:
|
||||
titles:
|
||||
team-invite-panel: Spieler einladen
|
||||
button:
|
||||
already-invited: "&c Bereits eingeladen"
|
||||
search: "&a Suche nach einem Spieler"
|
||||
searching: |
|
||||
&b Suche nach
|
||||
&c [name]
|
||||
enter-name: "&a Namen eingeben:"
|
||||
tips:
|
||||
LEFT:
|
||||
name: "&b Linksklick"
|
||||
search: "&a Geben Sie den Namen des Spielers ein"
|
||||
back: "&a Zurück"
|
||||
invite: |
|
||||
&a, um einen Spieler einzuladen
|
||||
&a, um deinem Team beizutreten
|
||||
RIGHT:
|
||||
name: "&b Rechtsklick"
|
||||
coop: "&a an Koop-Spieler"
|
||||
SHIFT_LEFT:
|
||||
name: "&b Umschalttaste Linksklick"
|
||||
trust: "&a einem Spieler vertrauen"
|
||||
errors:
|
||||
cannot-invite-self: "&c Du kannst dich nicht selbst einladen!"
|
||||
cooldown: "&c Du kannst diese Person für weitere [number] Sekunden nicht
|
||||
@ -690,12 +792,14 @@ commands:
|
||||
you-joined-island: "&a Du bist einer Insel beigetreten! Benutze /[label]
|
||||
team info um die anderen Mitglieder zu sehen."
|
||||
name-joined-your-island: "&a [name] hat sich deiner Insel angeschlossen!"
|
||||
confirmation: |-
|
||||
&c Bist du sicher, dass du diese Einladung annehmen willst?
|
||||
&c&l Du &n VERLIERST&r&c&l deine jetzige Insel!
|
||||
confirmation: |
|
||||
&c Sind Sie sicher, dass Sie
|
||||
&c diese
|
||||
&c Einladung annehmen möchten?
|
||||
reject:
|
||||
description: eine Einladung ablehnen
|
||||
you-rejected-invite: "&a Du hast die Einladung, einer Insel beizutreten, abgelehnt."
|
||||
you-rejected-invite: "&a Du hast die Einladung, einer Insel beizutreten,
|
||||
abgelehnt."
|
||||
name-rejected-your-invite: "&c [name] hat deine Insel-Einladung abgelehnt!"
|
||||
cancel:
|
||||
description: die ausstehende Einladung zu deiner Insel zurücknehmen
|
||||
@ -718,6 +822,7 @@ commands:
|
||||
errors:
|
||||
cant-demote-yourself: "&c Du kannst dich nicht selbst zurückstufen!"
|
||||
cant-demote: "&c Sie können keine höheren Ränge herabstufen!"
|
||||
must-be-member: "&c Der Spieler muss ein Inselmitglied sein!"
|
||||
failure: "&c Der Spieler kann nicht weiter zurückgestuft werden!"
|
||||
success: "&a Rückstufung von [name] auf [rank]."
|
||||
promote:
|
||||
@ -726,6 +831,7 @@ commands:
|
||||
errors:
|
||||
cant-promote-yourself: "&c Du kannst dich nicht bewerben!"
|
||||
cant-promote: "&c Sie können nicht über Ihren Rang hinaus aufsteigen!"
|
||||
must-be-member: "&c Der Spieler muss ein Inselmitglied sein!"
|
||||
failure: "&c Der Spieler kann nicht weiter befördert werden!"
|
||||
success: "&a Beförderung von [name] auf [rank]."
|
||||
setowner:
|
||||
@ -820,6 +926,10 @@ protection:
|
||||
description: Interaktion umschalten
|
||||
name: Leuchtfeuer
|
||||
hint: Leuchtfeuer-Nutzung deaktiviert
|
||||
BELL_RINGING:
|
||||
description: Interaktion umschalten
|
||||
name: Klingeln zulassen
|
||||
hint: Klingeln deaktiviert
|
||||
BED:
|
||||
description: Interaktion umschalten
|
||||
name: Betten
|
||||
@ -866,6 +976,10 @@ protection:
|
||||
description: Umschalten der Knopfnutzung
|
||||
name: Knöpfe
|
||||
hint: Nutzung von Knöpfen deaktiviert
|
||||
CANDLES:
|
||||
description: Kerzeninteraktion umschalten
|
||||
name: Kerzen
|
||||
hint: Kerzeninteraktion deaktiviert
|
||||
CAKE:
|
||||
description: Kuchen Interaktion umschalten
|
||||
name: Kuchen
|
||||
@ -1102,6 +1216,11 @@ protection:
|
||||
description: "&a Bienenstockernte umschalten."
|
||||
name: Bienenstockernte
|
||||
hint: Ernte behindert
|
||||
HURT_TAMED_ANIMALS:
|
||||
description: Verletzen ein-/ausschalten. Aktiviert bedeutet, dass gezähmte Tiere
|
||||
Schaden nehmen können. Deaktiviert bedeutet, dass sie unbesiegbar sind.
|
||||
name: Verletzte gezähmte Tiere
|
||||
hint: Gezähmtes Tier, das Behinderte verletzt
|
||||
HURT_ANIMALS:
|
||||
description: Umschalten des Verletzens
|
||||
name: Tiere verletzen
|
||||
@ -1147,6 +1266,7 @@ protection:
|
||||
LEASH:
|
||||
description: Umschalten der Nutzung
|
||||
name: Leine benutzen
|
||||
hint: Leinengebrauch deaktiviert
|
||||
LECTERN:
|
||||
name: Lesepulte
|
||||
description: "&a Erlaubt es, Bücher auf ein Lesepult zu legen \n&a oder Bücher
|
||||
@ -1469,14 +1589,6 @@ protection:
|
||||
&7 Aktuelle Einstellung: [setting]
|
||||
setting-active: "&a Aktiv"
|
||||
setting-disabled: "&c Deaktiviert"
|
||||
language:
|
||||
panel-title: Wähle deine Sprache
|
||||
description:
|
||||
selected: "&a Derzeit ausgewählt."
|
||||
click-to-select: "&e Klick &a zum Auswählen"
|
||||
authors: "&a Autoren:"
|
||||
author: "&3 - &b [name]"
|
||||
edited: "&a Die Sprache wurde geändert auf &e [lang]&a ."
|
||||
management:
|
||||
panel:
|
||||
title: BentoBox Verwaltung
|
||||
@ -1586,6 +1698,10 @@ enums:
|
||||
HOT_FLOOR: Heißer Boden
|
||||
CRAMMING: Pauken
|
||||
DRYOUT: Austrocknen
|
||||
FREEZE: Einfrieren
|
||||
KILL: Töten
|
||||
SONIC_BOOM: Überschallknall
|
||||
WORLD_BORDER: Weltgrenze
|
||||
panel:
|
||||
credits:
|
||||
title: "&8 [name] &2 Credits"
|
||||
@ -1597,6 +1713,42 @@ panel:
|
||||
description: "&c BentoBox konnte die Mitwirkenden \n&c für dieses Addon nicht
|
||||
erfassen.\n\n&a BentoBox erlauben, sich mit GitHub in \n&a der Konfiguration
|
||||
zu verbinden oder es später erneut versuchen."
|
||||
panels:
|
||||
island_creation:
|
||||
title: "&2&l Wähle eine Insel"
|
||||
buttons:
|
||||
bundle:
|
||||
name: "&l [name]"
|
||||
description: "[description]"
|
||||
uses: "&a Verwendet [number]/[max]"
|
||||
unlimited: "&a Unbegrenzte Nutzung erlaubt"
|
||||
language:
|
||||
title: "&2&l Wählen Sie Ihre Sprache"
|
||||
buttons:
|
||||
language:
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[authors]
|
||||
|[selected]
|
||||
authors: "&7 Autoren:"
|
||||
author: "&7 - &b [name]"
|
||||
selected: "&a Aktuell ausgewählt."
|
||||
buttons:
|
||||
previous:
|
||||
name: "&f&l Vorherige Seite"
|
||||
description: "&7 Zur Seite [number] wechseln"
|
||||
next:
|
||||
name: "&f&l Nächste Seite"
|
||||
description: "&7 Zur Seite [number] wechseln"
|
||||
tips:
|
||||
click-to-next: "&e Klicken Sie auf &7, um weiterzugehen."
|
||||
click-to-previous: "&e Klicken Sie auf &7, um zum vorherigen zu gelangen."
|
||||
click-to-choose: "&e Klicken Sie zum Auswählen auf &7."
|
||||
click-to-toggle: "&e Klicken Sie zum Umschalten auf &7."
|
||||
left-click-to-cycle-down: "&e Klicken Sie mit der linken Maustaste auf &7, um
|
||||
nach unten zu blättern."
|
||||
right-click-to-cycle-up: "&e Klicken Sie mit der rechten Maustaste auf &7, um
|
||||
nach oben zu blättern."
|
||||
successfully-loaded: |-
|
||||
&6 ____ _ ____
|
||||
&6 | _ \ | | | _ \ &7 by &a tastybento &7 and &a Poslovitch
|
||||
|
@ -127,6 +127,7 @@ public class IslandSpawnCommandTest {
|
||||
when(plugin.getSettings()).thenReturn(s);
|
||||
|
||||
// IWM
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.getWorldSettings(any())).thenReturn(ws);
|
||||
map = new HashMap<>();
|
||||
|
@ -244,7 +244,7 @@ public class IslandTeamInviteCommandTest extends RanksManagerBeforeClassTest {
|
||||
*/
|
||||
@Test
|
||||
public void testCanExecuteNoTarget() {
|
||||
assertTrue(itl.canExecute(user, itl.getLabel(), Collections.emptyList()));
|
||||
assertFalse(itl.canExecute(user, itl.getLabel(), Collections.emptyList()));
|
||||
// Show panel
|
||||
verify(p).openInventory(any(Inventory.class));
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ public class IslandTeamLeaveCommandTest {
|
||||
when(Bukkit.getScheduler()).thenReturn(sch);
|
||||
|
||||
// Island World Manager
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
|
||||
// Plugin Manager
|
||||
|
@ -119,11 +119,16 @@ public class UserTest {
|
||||
// Player
|
||||
when(player.getServer()).thenReturn(server);
|
||||
when(server.getOnlinePlayers()).thenReturn(Collections.emptySet());
|
||||
@NonNull
|
||||
World world = mock(World.class);
|
||||
when(world.getName()).thenReturn("BSkyBlock");
|
||||
when(player.getWorld()).thenReturn(world);
|
||||
|
||||
// IWM
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
// Addon
|
||||
when(iwm .getAddon(any())).thenReturn(Optional.empty());
|
||||
when(iwm.getAddon(any())).thenReturn(Optional.empty());
|
||||
when(iwm.getFriendlyName(world)).thenReturn("BSkyBlock-Fiendly");
|
||||
|
||||
user = User.getInstance(player);
|
||||
|
||||
@ -930,7 +935,7 @@ public class UserTest {
|
||||
when(addon.getDescription()).thenReturn(new Builder("main", "gameAddon", "1.0").build());
|
||||
p.setAddon(addon);
|
||||
p.getTranslation(TEST_TRANSLATION);
|
||||
verify(addon).getDescription();
|
||||
verify(addon, times(3)).getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,6 +77,7 @@ public class BannedCommandsTest {
|
||||
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
|
||||
when(iwm.getVisitorBannedCommands(any())).thenReturn(new ArrayList<>());
|
||||
when(iwm.getFallingBannedCommands(any())).thenReturn(new ArrayList<>());
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
WorldSettings ws = new MyWorldSettings();
|
||||
when(iwm.getWorldSettings(any())).thenReturn(ws);
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
|
@ -134,6 +134,7 @@ public class JoinLeaveListenerTest {
|
||||
when(iwm.getAddon(any())).thenReturn(opGm);
|
||||
when(gameMode.getPermissionPrefix()).thenReturn("acidisland.");
|
||||
when(iwm.getIslandDistance(any())).thenReturn(100);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
|
||||
UUID uuid = UUID.randomUUID();
|
||||
// Player
|
||||
|
@ -110,6 +110,7 @@ public class StandardSpawnProtectionListenerTest extends AbstractCommonSetup {
|
||||
when(iwm.inWorld(any(World.class))).thenReturn(true);
|
||||
when(iwm.getNetherSpawnRadius(any())).thenReturn(25);
|
||||
when(iwm.getWorldSettings(any())).thenReturn(ws);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
// Util
|
||||
PowerMockito.mockStatic(Util.class);
|
||||
when(Util.getWorld(any())).thenReturn(world);
|
||||
|
@ -138,6 +138,7 @@ public abstract class AbstractCommonSetup {
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
when(iwm.inWorld(any(Location.class))).thenReturn(true);
|
||||
when(iwm.inWorld(any(World.class))).thenReturn(true);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
// Addon
|
||||
when(iwm.getAddon(any())).thenReturn(Optional.empty());
|
||||
|
||||
|
@ -250,10 +250,11 @@ public class EntityInteractListenerTest extends AbstractCommonSetup {
|
||||
clickedEntity = mock(WanderingTrader.class);
|
||||
when(clickedEntity.getLocation()).thenReturn(location);
|
||||
when(clickedEntity.getType()).thenReturn(EntityType.WANDERING_TRADER);
|
||||
when(inv.getItemInMainHand()).thenReturn(new ItemStack(Material.STONE));
|
||||
PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(mockPlayer, clickedEntity, hand);
|
||||
eil.onPlayerInteractEntity(e);
|
||||
verify(notifier, times(2)).notify(any(), eq("protection.protected"));
|
||||
assertTrue(e.isCancelled());
|
||||
verify(notifier, never()).notify(any(), eq("protection.protected"));
|
||||
assertFalse(e.isCancelled());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,8 +287,8 @@ public class EntityInteractListenerTest extends AbstractCommonSetup {
|
||||
when(clickedEntity.getLocation()).thenReturn(location);
|
||||
PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(mockPlayer, clickedEntity, hand);
|
||||
eil.onPlayerInteractEntity(e);
|
||||
verify(notifier).notify(any(), eq("protection.protected"));
|
||||
assertTrue(e.isCancelled());
|
||||
verify(notifier, never()).notify(any(), eq("protection.protected"));
|
||||
assertFalse(e.isCancelled());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,6 +136,7 @@ public class PVPListenerTest {
|
||||
when(iwm.inWorld(any(World.class))).thenReturn(true);
|
||||
when(iwm.inWorld(any(Location.class))).thenReturn(true);
|
||||
when(iwm.getPermissionPrefix(Mockito.any())).thenReturn("bskyblock.");
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
// No visitor protection right now
|
||||
when(iwm.getIvSettings(any())).thenReturn(new ArrayList<>());
|
||||
when(plugin.getIWM()).thenReturn(iwm);
|
||||
|
@ -114,6 +114,7 @@ public class ObsidianScoopingListenerTest {
|
||||
when(iwm.getIslandWorld(Mockito.any())).thenReturn(world);
|
||||
when(iwm.getNetherWorld(Mockito.any())).thenReturn(world);
|
||||
when(iwm.getEndWorld(Mockito.any())).thenReturn(world);
|
||||
when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock");
|
||||
|
||||
// Mock up IslandsManager
|
||||
when(plugin.getIslands()).thenReturn(im);
|
||||
|
@ -0,0 +1,48 @@
|
||||
package world.bentobox.bentobox.util;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ExpiringMapTest {
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.util.ExpiringMap#ExpiringMap(long, java.util.concurrent.TimeUnit)}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testExpiringMap() throws InterruptedException {
|
||||
ExpiringMap<String, String> expiringMap = new ExpiringMap<>(5, TimeUnit.SECONDS);
|
||||
|
||||
expiringMap.put("key1", "value1");
|
||||
assertEquals(1, expiringMap.size());
|
||||
|
||||
// Check if key1 is present
|
||||
assertTrue(expiringMap.containsKey("key1"));
|
||||
|
||||
// Using computeIfAbsent
|
||||
String value = expiringMap.computeIfAbsent("key2", k -> "computedValue");
|
||||
assertEquals("computedValue", value);
|
||||
assertEquals(2, expiringMap.size());
|
||||
|
||||
// Check if key2 is present
|
||||
assertTrue(expiringMap.containsKey("key2"));
|
||||
|
||||
// Use Awaitility to wait for keys to expire
|
||||
await().atMost(Duration.ofSeconds(6))
|
||||
.until(() -> !expiringMap.containsKey("key1") && !expiringMap.containsKey("key2"));
|
||||
|
||||
assertFalse(expiringMap.containsKey("key1"));
|
||||
assertFalse(expiringMap.containsKey("key2"));
|
||||
assertTrue(expiringMap.isEmpty());
|
||||
|
||||
expiringMap.shutdown();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user