Player configuration API with default implementation on paper server.
Also merging pandalib-paper-player into pandalib-paper due to unavoidable circular dependency
This commit is contained in:
parent
7b0793ae38
commit
b756b912bd
@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>pandalib-parent</artifactId>
|
|
||||||
<groupId>fr.pandacube.lib</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>pandalib-paper-players</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>papermc</id>
|
|
||||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>fr.pandacube.lib</groupId>
|
|
||||||
<artifactId>pandalib-players</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Paper -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.papermc.paper</groupId>
|
|
||||||
<artifactId>paper-api</artifactId>
|
|
||||||
<version>${paper.version}-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.papermc.paper</groupId>
|
|
||||||
<artifactId>paper-mojangapi</artifactId>
|
|
||||||
<version>${paper.version}-SNAPSHOT</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
@ -7,6 +7,8 @@ import org.bukkit.scoreboard.Team;
|
|||||||
|
|
||||||
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
|
import fr.pandacube.lib.players.standalone.AbstractOffPlayer;
|
||||||
|
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents any player on a paper server, either offline or online.
|
* Represents any player on a paper server, either offline or online.
|
||||||
*/
|
*/
|
||||||
@ -94,4 +96,37 @@ public interface PaperOffPlayer extends AbstractOffPlayer {
|
|||||||
return teamPrefix + teamColor + name + teamSuffix;
|
return teamPrefix + teamColor + name + teamSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Player config
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getConfig(String key) throws Exception {
|
||||||
|
return PaperPlayerConfigStorage.get(getUniqueId(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getConfig(String key, String deflt) throws Exception {
|
||||||
|
return PaperPlayerConfigStorage.get(getUniqueId(), key, deflt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void setConfig(String key, String value) throws Exception {
|
||||||
|
PaperPlayerConfigStorage.set(getUniqueId(), key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void updateConfig(String key, String deflt, UnaryOperator<String> updater) throws Exception {
|
||||||
|
PaperPlayerConfigStorage.update(getUniqueId(), key, deflt, updater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void unsetConfig(String key) throws Exception {
|
||||||
|
PaperPlayerConfigStorage.unset(getUniqueId(), key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,213 @@
|
|||||||
|
package fr.pandacube.lib.paper.players;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.paper.PandaLibPaper;
|
||||||
|
import fr.pandacube.lib.util.Log;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class PaperPlayerConfigStorage {
|
||||||
|
|
||||||
|
static File storageFile = new File(PandaLibPaper.getPlugin().getDataFolder(), "playerdata.yml");
|
||||||
|
static boolean initialized = false;
|
||||||
|
|
||||||
|
static LinkedHashMap<ConfigKey, ConfigEntry> data = new LinkedHashMap<>();
|
||||||
|
static LinkedHashMap<UUID, LinkedHashSet<ConfigEntry>> playerSortedData = new LinkedHashMap<>();
|
||||||
|
static LinkedHashMap<String, LinkedHashSet<ConfigEntry>> keySortedData = new LinkedHashMap<>();
|
||||||
|
static boolean changed = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static synchronized void initIfNeeded() {
|
||||||
|
if (initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
load();
|
||||||
|
} catch (InvalidConfigurationException|IOException e) {
|
||||||
|
throw new RuntimeException("Unable to load the player data file.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto-save every 30 seconds
|
||||||
|
Bukkit.getScheduler().runTaskTimerAsynchronously(PandaLibPaper.getPlugin(), PaperPlayerConfigStorage::save, 600, 600);
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static synchronized void load() throws IOException, InvalidConfigurationException {
|
||||||
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
|
config.load(storageFile);
|
||||||
|
data.clear();
|
||||||
|
playerSortedData.clear();
|
||||||
|
keySortedData.clear();
|
||||||
|
for (String pIdStr : config.getKeys(false)) {
|
||||||
|
UUID pId;
|
||||||
|
try {
|
||||||
|
pId = UUID.fromString(pIdStr);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.severe("Invalid player UUID: '" + pIdStr + "'", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ConfigurationSection sec = config.getConfigurationSection(pIdStr);
|
||||||
|
for (String key : sec.getKeys(false)) {
|
||||||
|
String value = sec.getString(key);
|
||||||
|
create(pId, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static synchronized void save() {
|
||||||
|
YamlConfiguration config = new YamlConfiguration();
|
||||||
|
for (UUID pId : playerSortedData.keySet()) {
|
||||||
|
String pIdStr = pId.toString();
|
||||||
|
ConfigurationSection sec = new YamlConfiguration();
|
||||||
|
for (ConfigEntry e : playerSortedData.get(pId)) {
|
||||||
|
sec.set(e.key, e.value);
|
||||||
|
}
|
||||||
|
config.set(pIdStr, sec);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.save(storageFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to save the player data file.", e);
|
||||||
|
}
|
||||||
|
changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static synchronized void create(UUID player, String key, String newValue) {
|
||||||
|
ConfigKey cKey = new ConfigKey(player, key);
|
||||||
|
ConfigEntry e = new ConfigEntry(player, key, newValue);
|
||||||
|
data.put(cKey, e);
|
||||||
|
playerSortedData.computeIfAbsent(player, p -> new LinkedHashSet<>()).add(e);
|
||||||
|
keySortedData.computeIfAbsent(key, p -> new LinkedHashSet<>()).add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static synchronized void set(UUID player, String key, String newValue) {
|
||||||
|
initIfNeeded();
|
||||||
|
ConfigKey cKey = new ConfigKey(player, key);
|
||||||
|
ConfigEntry e = data.get(cKey);
|
||||||
|
if (e != null && newValue == null) { // delete
|
||||||
|
data.remove(cKey);
|
||||||
|
if (playerSortedData.containsKey(player))
|
||||||
|
playerSortedData.get(player).remove(e);
|
||||||
|
if (keySortedData.containsKey(key))
|
||||||
|
keySortedData.get(key).remove(e);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if (e == null && newValue != null) { // create
|
||||||
|
create(player, key, newValue);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else if (e != null && !newValue.equals(e.value)) { // update
|
||||||
|
e.value = newValue;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized String get(UUID player, String key) {
|
||||||
|
initIfNeeded();
|
||||||
|
ConfigEntry e = data.get(new ConfigKey(player, key));
|
||||||
|
return e != null ? e.value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String get(UUID p, String k, String deflt) {
|
||||||
|
String value = get(p, k);
|
||||||
|
return value == null ? deflt : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void update(UUID p, String k, String deflt, UnaryOperator<String> updater) {
|
||||||
|
String oldValue = get(p, k, deflt);
|
||||||
|
set(p, k, updater.apply(oldValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unset(UUID p, String k) {
|
||||||
|
set(p, k, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static LinkedHashSet<ConfigEntry> getAllFromPlayer(UUID p) {
|
||||||
|
initIfNeeded();
|
||||||
|
return new LinkedHashSet<>(playerSortedData.getOrDefault(p, new LinkedHashSet<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkedHashSet<ConfigEntry> getAllWithKeys(String key) {
|
||||||
|
initIfNeeded();
|
||||||
|
return new LinkedHashSet<>(keySortedData.getOrDefault(key, new LinkedHashSet<>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkedHashSet<ConfigEntry> getAllWithKeyValue(String k, String v) {
|
||||||
|
initIfNeeded();
|
||||||
|
return getAllWithKeys(k).stream()
|
||||||
|
.filter(c -> c.value.equals(v))
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private record ConfigKey(UUID playerId, String key) { }
|
||||||
|
|
||||||
|
public static class ConfigEntry {
|
||||||
|
private final UUID playerId;
|
||||||
|
private final String key;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
private ConfigEntry(UUID playerId, String key, String value) {
|
||||||
|
this.playerId = playerId;
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getPlayerId() {
|
||||||
|
return playerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(playerId, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof ConfigEntry o
|
||||||
|
&& Objects.equals(playerId, o.playerId)
|
||||||
|
&& Objects.equals(key, o.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package fr.pandacube.lib.players.standalone;
|
package fr.pandacube.lib.players.standalone;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents any player, either offline or online.
|
* Represents any player, either offline or online.
|
||||||
@ -65,6 +66,24 @@ public interface AbstractOffPlayer {
|
|||||||
*/
|
*/
|
||||||
String getDisplayName();
|
String getDisplayName();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Player config
|
||||||
|
*/
|
||||||
|
|
||||||
|
String getConfig(String key) throws Exception;
|
||||||
|
|
||||||
|
String getConfig(String key, String deflt) throws Exception;
|
||||||
|
|
||||||
|
void setConfig(String key, String value) throws Exception;
|
||||||
|
|
||||||
|
void updateConfig(String key, String deflt, UnaryOperator<String> updater) throws Exception;
|
||||||
|
|
||||||
|
void unsetConfig(String key) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user