mirror of
https://github.com/CarmJos/EasyPlugin.git
synced 2026-06-04 08:38:17 +08:00
feat(users): Seperated users registry interface for api usage.
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyplugin-parent</artifactId>
|
||||
<version>1.5.12</version>
|
||||
<version>1.5.13</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package cc.carm.lib.easyplugin.user;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractUserData<K> implements UserData<K> {
|
||||
|
||||
protected final @NotNull K key;
|
||||
|
||||
/**
|
||||
* Used to mark the data as dropping (save and unload) status.
|
||||
*/
|
||||
protected boolean dropping = false;
|
||||
|
||||
protected AbstractUserData(@NotNull K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dropping true if the data is dropping, false otherwise
|
||||
*/
|
||||
public void setDropping(boolean dropping) {
|
||||
this.dropping = dropping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the data is dropping, false otherwise
|
||||
*/
|
||||
public boolean isDropping() {
|
||||
return dropping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AbstractUserData<?> abstractUserData = (AbstractUserData<?>) o;
|
||||
return key.equals(abstractUserData.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,31 +2,22 @@ package cc.carm.lib.easyplugin.user;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
public interface UserData<K> {
|
||||
|
||||
public abstract class UserData<K> {
|
||||
@NotNull K key();
|
||||
|
||||
protected final @NotNull K key;
|
||||
|
||||
protected UserData(@NotNull K key) {
|
||||
this.key = key;
|
||||
@Deprecated
|
||||
default @NotNull K getKey() {
|
||||
return key();
|
||||
}
|
||||
|
||||
public @NotNull K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
UserData<?> userData = (UserData<?>) o;
|
||||
return key.equals(userData.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(key);
|
||||
}
|
||||
/**
|
||||
* @param dropping true if the data is dropping, false otherwise
|
||||
*/
|
||||
void setDropping(boolean dropping);
|
||||
|
||||
/**
|
||||
* @return true if the data is dropping, false otherwise
|
||||
*/
|
||||
boolean isDropping();
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package cc.carm.lib.easyplugin.user;
|
||||
|
||||
import cc.carm.lib.easyplugin.EasyPlugin;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -21,7 +18,7 @@ import java.util.function.Supplier;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
public abstract class UserDataManager<K, U extends AbstractUserData<K>> implements UserDataRegistry<K, U> {
|
||||
|
||||
protected final @NotNull EasyPlugin plugin;
|
||||
|
||||
@@ -47,6 +44,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
this.dataCache = cacheMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
this.executor.shutdown();
|
||||
}
|
||||
@@ -55,14 +53,11 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
protected @NotNull Logger getLogger() {
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return getPlugin().getLogger();
|
||||
}
|
||||
|
||||
public String serializeKey(@NotNull K key) {
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
public abstract @NotNull U emptyUser(@NotNull K key);
|
||||
|
||||
public @NotNull U errorUser(@NotNull K key) {
|
||||
@@ -73,36 +68,16 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
|
||||
protected abstract void saveData(@NotNull U data) throws Exception;
|
||||
|
||||
public @NotNull CompletableFuture<U> load(@NotNull K key) {
|
||||
return load(key, false);
|
||||
}
|
||||
|
||||
public @NotNull CompletableFuture<U> load(@NotNull K key, boolean cache) {
|
||||
return load(key, () -> cache);
|
||||
}
|
||||
|
||||
public @NotNull Map<K, U> getDataCache() {
|
||||
return dataCache;
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
public @NotNull Set<U> list() {
|
||||
return ImmutableSet.copyOf(getDataCache().values());
|
||||
}
|
||||
|
||||
public @NotNull U get(@NotNull K key) {
|
||||
return Optional.ofNullable(getNullable(key)).orElseThrow(() -> new NullPointerException("User " + key + " not found."));
|
||||
}
|
||||
|
||||
public @Nullable U getNullable(@NotNull K key) {
|
||||
return getDataCache().get(key);
|
||||
}
|
||||
|
||||
public @NotNull Optional<@Nullable U> getOptional(@NotNull K key) {
|
||||
return Optional.ofNullable(getNullable(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<U> load(@NotNull K key, @NotNull Supplier<Boolean> cacheCondition) {
|
||||
U cached = getNullable(key);
|
||||
if (cached != null) {
|
||||
return CompletableFuture.supplyAsync(() -> cached); // Return cached data async.
|
||||
}
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
String identifier = serializeKey(key);
|
||||
|
||||
@@ -124,11 +99,12 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
}
|
||||
|
||||
}, executor).thenApply((data) -> {
|
||||
if (cacheCondition.get()) dataCache.put(key, data);
|
||||
if (cacheCondition.get() && !data.isDropping()) dataCache.put(key, data);
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Boolean> save(@NotNull U user) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
String identifier = serializeKey(user.getKey());
|
||||
@@ -148,17 +124,18 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
}, executor);
|
||||
}
|
||||
|
||||
public @NotNull CompletableFuture<Boolean> unload(@NotNull K key) {
|
||||
return unload(key, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Boolean> unload(@NotNull K key, boolean save) {
|
||||
U data = getNullable(key);
|
||||
if (data == null) return CompletableFuture.completedFuture(false);
|
||||
|
||||
data.setDropping(true); // Mark the data as unloading.
|
||||
if (save) {
|
||||
return save(data).thenApply(result -> {
|
||||
this.dataCache.remove(key);
|
||||
// Check if the data is still unloading,
|
||||
// which cloud be interrupted by the next load.
|
||||
if (data.isDropping()) {
|
||||
this.dataCache.remove(key);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
} else {
|
||||
@@ -168,6 +145,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<Boolean> modify(@NotNull K key, @NotNull Consumer<U> consumer) {
|
||||
U cached = getNullable(key);
|
||||
if (cached != null) {
|
||||
@@ -176,13 +154,14 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
return true;
|
||||
}, executor);
|
||||
} else {
|
||||
return load(key, false).thenApply((data) -> {
|
||||
return load(key, true).thenApply((data) -> {
|
||||
consumer.accept(data);
|
||||
return data;
|
||||
}).thenCompose(this::save);
|
||||
}).thenCompose(data -> unload(key, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> @NotNull CompletableFuture<V> peek(@NotNull K key, @NotNull Function<U, V> function) {
|
||||
U cached = getNullable(key);
|
||||
if (cached != null) {
|
||||
@@ -192,10 +171,6 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull CompletableFuture<Map<K, U>> loadOnline(@NotNull Function<Player, ? extends K> function) {
|
||||
return loadGroup(Bukkit.getOnlinePlayers(), function, OfflinePlayer::isOnline);
|
||||
}
|
||||
|
||||
public <T> @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<? extends T> users,
|
||||
@NotNull Function<? super T, ? extends K> function,
|
||||
@NotNull Predicate<T> cacheCondition) {
|
||||
@@ -218,15 +193,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
return task.thenApply(Collections::unmodifiableMap);
|
||||
}
|
||||
|
||||
public @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<K> allKeys,
|
||||
@NotNull Predicate<K> cacheCondition) {
|
||||
return loadGroup(allKeys, Function.identity(), cacheCondition);
|
||||
}
|
||||
|
||||
public @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<K> allKeys) {
|
||||
return loadGroup(allKeys, (v) -> false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
if (getDataCache().isEmpty()) return;
|
||||
for (U u : getDataCache().values()) {
|
||||
@@ -239,6 +206,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int unloadAll(boolean save) {
|
||||
if (save) saveAll();
|
||||
int size = getDataCache().size();
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package cc.carm.lib.easyplugin.user;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface UserDataRegistry<K, U extends UserData<K>> {
|
||||
|
||||
void shutdown();
|
||||
|
||||
@NotNull Logger getLogger();
|
||||
|
||||
|
||||
@NotNull Map<K, U> cache();
|
||||
|
||||
default String serializeKey(@NotNull K key) {
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
default @NotNull CompletableFuture<U> load(@NotNull K key) {
|
||||
return load(key, false);
|
||||
}
|
||||
|
||||
default @NotNull CompletableFuture<U> load(@NotNull K key, boolean cache) {
|
||||
return load(key, () -> cache);
|
||||
}
|
||||
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull Set<U> list() {
|
||||
return ImmutableSet.copyOf(cache().values());
|
||||
}
|
||||
|
||||
default @NotNull U get(@NotNull K key) {
|
||||
return Optional.ofNullable(getNullable(key)).orElseThrow(() -> new NullPointerException("User " + key + " not found."));
|
||||
}
|
||||
|
||||
default @Nullable U getNullable(@NotNull K key) {
|
||||
return cache().get(key);
|
||||
}
|
||||
|
||||
default @NotNull Optional<@Nullable U> getOptional(@NotNull K key) {
|
||||
return Optional.ofNullable(getNullable(key));
|
||||
}
|
||||
|
||||
@NotNull CompletableFuture<U> load(@NotNull K key, @NotNull Supplier<Boolean> cacheCondition);
|
||||
|
||||
@NotNull CompletableFuture<Boolean> save(@NotNull U user);
|
||||
|
||||
default @NotNull CompletableFuture<Boolean> unload(@NotNull K key) {
|
||||
return unload(key, true);
|
||||
}
|
||||
|
||||
@NotNull CompletableFuture<Boolean> unload(@NotNull K key, boolean save);
|
||||
|
||||
@NotNull CompletableFuture<Boolean> modify(@NotNull K key, @NotNull Consumer<U> consumer);
|
||||
|
||||
<V> @NotNull CompletableFuture<V> peek(@NotNull K key, @NotNull Function<U, V> function);
|
||||
|
||||
default @NotNull CompletableFuture<Map<K, U>> loadOnline(@NotNull Function<Player, ? extends K> function) {
|
||||
return loadGroup(Bukkit.getOnlinePlayers(), function, OfflinePlayer::isOnline);
|
||||
}
|
||||
|
||||
<T> @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<? extends T> users,
|
||||
@NotNull Function<? super T, ? extends K> function,
|
||||
@NotNull Predicate<T> cacheCondition);
|
||||
|
||||
default @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<K> allKeys,
|
||||
@NotNull Predicate<K> cacheCondition) {
|
||||
return loadGroup(allKeys, Function.identity(), cacheCondition);
|
||||
}
|
||||
|
||||
default @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<K> allKeys) {
|
||||
return loadGroup(allKeys, (v) -> false);
|
||||
}
|
||||
|
||||
void saveAll();
|
||||
|
||||
int unloadAll(boolean save);
|
||||
}
|
||||
Reference in New Issue
Block a user