1
mirror of https://github.com/CarmJos/EasyPlugin.git synced 2026-06-04 16:48:16 +08:00

feat(users): Seperated users registry interface for api usage.

This commit is contained in:
2025-05-17 03:44:07 +08:00
parent bc3dd32f85
commit 54939f0f14
21 changed files with 219 additions and 97 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+21
View File
@@ -0,0 +1,21 @@
import org.junit.Test;
public class PageTest {
@Test
public void test() {
System.out.println(maxPage(0, 10));
System.out.println(maxPage(10, 10));
System.out.println(maxPage(5, 10));
System.out.println(maxPage(15, 10));
System.out.println(maxPage(19, 10));
System.out.println(maxPage(20, 10));
}
int maxPage(int contents, int size) {
if (contents == 0 || size == 0) return 1;
return (contents / size) + ((contents % size) == 0 ? 0 : 1);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <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 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; @Deprecated
default @NotNull K getKey() {
protected UserData(@NotNull K key) { return key();
this.key = key;
} }
public @NotNull K getKey() { /**
return key; * @param dropping true if the data is dropping, false otherwise
} */
void setDropping(boolean dropping);
@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);
}
/**
* @return true if the data is dropping, false otherwise
*/
boolean isDropping();
} }
@@ -1,15 +1,12 @@
package cc.carm.lib.easyplugin.user; package cc.carm.lib.easyplugin.user;
import cc.carm.lib.easyplugin.EasyPlugin; 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.NotNull;
import org.jetbrains.annotations.Nullable; 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.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -21,7 +18,7 @@ import java.util.function.Supplier;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; 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; protected final @NotNull EasyPlugin plugin;
@@ -47,6 +44,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
this.dataCache = cacheMap; this.dataCache = cacheMap;
} }
@Override
public void shutdown() { public void shutdown() {
this.executor.shutdown(); this.executor.shutdown();
} }
@@ -55,14 +53,11 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
return plugin; return plugin;
} }
protected @NotNull Logger getLogger() { @Override
public @NotNull Logger getLogger() {
return getPlugin().getLogger(); return getPlugin().getLogger();
} }
public String serializeKey(@NotNull K key) {
return key.toString();
}
public abstract @NotNull U emptyUser(@NotNull K key); public abstract @NotNull U emptyUser(@NotNull K key);
public @NotNull U errorUser(@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; 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() { public @NotNull Map<K, U> getDataCache() {
return dataCache; return dataCache;
} }
@Unmodifiable @Override
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));
}
public @NotNull CompletableFuture<U> load(@NotNull K key, @NotNull Supplier<Boolean> cacheCondition) { 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(() -> { return CompletableFuture.supplyAsync(() -> {
String identifier = serializeKey(key); String identifier = serializeKey(key);
@@ -124,11 +99,12 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
} }
}, executor).thenApply((data) -> { }, executor).thenApply((data) -> {
if (cacheCondition.get()) dataCache.put(key, data); if (cacheCondition.get() && !data.isDropping()) dataCache.put(key, data);
return data; return data;
}); });
} }
@Override
public @NotNull CompletableFuture<Boolean> save(@NotNull U user) { public @NotNull CompletableFuture<Boolean> save(@NotNull U user) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
String identifier = serializeKey(user.getKey()); String identifier = serializeKey(user.getKey());
@@ -148,17 +124,18 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
}, executor); }, executor);
} }
public @NotNull CompletableFuture<Boolean> unload(@NotNull K key) { @Override
return unload(key, true);
}
public @NotNull CompletableFuture<Boolean> unload(@NotNull K key, boolean save) { public @NotNull CompletableFuture<Boolean> unload(@NotNull K key, boolean save) {
U data = getNullable(key); U data = getNullable(key);
if (data == null) return CompletableFuture.completedFuture(false); if (data == null) return CompletableFuture.completedFuture(false);
data.setDropping(true); // Mark the data as unloading.
if (save) { if (save) {
return save(data).thenApply(result -> { return save(data).thenApply(result -> {
// Check if the data is still unloading,
// which cloud be interrupted by the next load.
if (data.isDropping()) {
this.dataCache.remove(key); this.dataCache.remove(key);
}
return result; return result;
}); });
} else { } 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) { public @NotNull CompletableFuture<Boolean> modify(@NotNull K key, @NotNull Consumer<U> consumer) {
U cached = getNullable(key); U cached = getNullable(key);
if (cached != null) { if (cached != null) {
@@ -176,13 +154,14 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
return true; return true;
}, executor); }, executor);
} else { } else {
return load(key, false).thenApply((data) -> { return load(key, true).thenApply((data) -> {
consumer.accept(data); consumer.accept(data);
return 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) { public <V> @NotNull CompletableFuture<V> peek(@NotNull K key, @NotNull Function<U, V> function) {
U cached = getNullable(key); U cached = getNullable(key);
if (cached != null) { 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, public <T> @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<? extends T> users,
@NotNull Function<? super T, ? extends K> function, @NotNull Function<? super T, ? extends K> function,
@NotNull Predicate<T> cacheCondition) { @NotNull Predicate<T> cacheCondition) {
@@ -218,15 +193,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
return task.thenApply(Collections::unmodifiableMap); return task.thenApply(Collections::unmodifiableMap);
} }
public @NotNull CompletableFuture<Map<K, U>> loadGroup(@NotNull Collection<K> allKeys, @Override
@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);
}
public void saveAll() { public void saveAll() {
if (getDataCache().isEmpty()) return; if (getDataCache().isEmpty()) return;
for (U u : getDataCache().values()) { for (U u : getDataCache().values()) {
@@ -239,6 +206,7 @@ public abstract class UserDataManager<K, U extends UserData<K>> {
} }
} }
@Override
public int unloadAll(boolean save) { public int unloadAll(boolean save) {
if (save) saveAll(); if (save) saveAll();
int size = getDataCache().size(); 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);
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>1.5.12</version> <version>1.5.13</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -15,7 +15,7 @@
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyplugin-parent</artifactId> <artifactId>easyplugin-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>1.5.12</version> <version>1.5.13</version>
<modules> <modules>
<module>base/color</module> <module>base/color</module>
<module>base/utils</module> <module>base/utils</module>