mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2025-02-03 21:41:30 +01:00
#1125 Create SingleFilePersistenceHandler + extract (de)serializer for LimboPlayer
This commit is contained in:
parent
8557621c02
commit
710198833c
@ -7,6 +7,8 @@ public enum LimboPersistenceType {
|
||||
|
||||
INDIVIDUAL_FILES(SeparateFilePersistenceHandler.class),
|
||||
|
||||
SINGLE_FILE(SingleFilePersistenceHandler.class),
|
||||
|
||||
DISABLED(NoOpPersistenceHandler.class);
|
||||
|
||||
private final Class<? extends LimboPersistenceHandler> implementationClass;
|
||||
|
@ -0,0 +1,115 @@
|
||||
package fr.xephi.authme.data.limbo.persistence;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.CAN_FLY;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.FLY_SPEED;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.GROUP;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.IS_OP;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOCATION;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_PITCH;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_WORLD;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_X;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Y;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_YAW;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.LOC_Z;
|
||||
import static fr.xephi.authme.data.limbo.persistence.LimboPlayerSerializer.WALK_SPEED;
|
||||
|
||||
/**
|
||||
* Converts a JsonElement to a LimboPlayer.
|
||||
*/
|
||||
class LimboPlayerDeserializer implements JsonDeserializer<LimboPlayer> {
|
||||
|
||||
private BukkitService bukkitService;
|
||||
|
||||
LimboPlayerDeserializer(BukkitService bukkitService) {
|
||||
this.bukkitService = bukkitService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimboPlayer deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) {
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
if (jsonObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Location loc = deserializeLocation(jsonObject);
|
||||
boolean operator = getBoolean(jsonObject, IS_OP);
|
||||
String group = getString(jsonObject, GROUP);
|
||||
boolean canFly = getBoolean(jsonObject, CAN_FLY);
|
||||
float walkSpeed = getFloat(jsonObject, WALK_SPEED, LimboPlayer.DEFAULT_WALK_SPEED);
|
||||
float flySpeed = getFloat(jsonObject, FLY_SPEED, LimboPlayer.DEFAULT_FLY_SPEED);
|
||||
|
||||
return new LimboPlayer(loc, operator, group, canFly, walkSpeed, flySpeed);
|
||||
}
|
||||
|
||||
private Location deserializeLocation(JsonObject jsonObject) {
|
||||
JsonElement e;
|
||||
if ((e = jsonObject.getAsJsonObject(LOCATION)) != null) {
|
||||
JsonObject locationObject = e.getAsJsonObject();
|
||||
World world = bukkitService.getWorld(getString(locationObject, LOC_WORLD));
|
||||
if (world != null) {
|
||||
double x = getDouble(locationObject, LOC_X);
|
||||
double y = getDouble(locationObject, LOC_Y);
|
||||
double z = getDouble(locationObject, LOC_Z);
|
||||
float yaw = getFloat(locationObject, LOC_YAW);
|
||||
float pitch = getFloat(locationObject, LOC_PITCH);
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getString(JsonObject jsonObject, String memberName) {
|
||||
JsonElement element = jsonObject.get(memberName);
|
||||
return element != null ? element.getAsString() : "";
|
||||
}
|
||||
|
||||
private static boolean getBoolean(JsonObject jsonObject, String memberName) {
|
||||
JsonElement element = jsonObject.get(memberName);
|
||||
return element != null && element.getAsBoolean();
|
||||
}
|
||||
|
||||
private static float getFloat(JsonObject jsonObject, String memberName) {
|
||||
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, 0.0f);
|
||||
}
|
||||
|
||||
private static float getFloat(JsonObject jsonObject, String memberName, float defaultValue) {
|
||||
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsFloat, defaultValue);
|
||||
}
|
||||
|
||||
private static double getDouble(JsonObject jsonObject, String memberName) {
|
||||
return getNumberFromElement(jsonObject.get(memberName), JsonElement::getAsDouble, 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a number from the given JsonElement safely.
|
||||
*
|
||||
* @param jsonElement the element to retrieve the number from
|
||||
* @param numberFunction the function to get the number from the element
|
||||
* @param defaultValue the value to return if the element is null or the number cannot be retrieved
|
||||
* @param <N> the number type
|
||||
* @return the number from the given JSON element, or the default value
|
||||
*/
|
||||
private static <N extends Number> N getNumberFromElement(JsonElement jsonElement,
|
||||
Function<JsonElement, N> numberFunction,
|
||||
N defaultValue) {
|
||||
if (jsonElement != null) {
|
||||
try {
|
||||
return numberFunction.apply(jsonElement);
|
||||
} catch (NumberFormatException ignore) {
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package fr.xephi.authme.data.limbo.persistence;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Converts a LimboPlayer to a JsonElement.
|
||||
*/
|
||||
class LimboPlayerSerializer implements JsonSerializer<LimboPlayer> {
|
||||
|
||||
static final String LOCATION = "location";
|
||||
static final String LOC_WORLD = "world";
|
||||
static final String LOC_X = "x";
|
||||
static final String LOC_Y = "y";
|
||||
static final String LOC_Z = "z";
|
||||
static final String LOC_YAW = "yaw";
|
||||
static final String LOC_PITCH = "pitch";
|
||||
|
||||
static final String GROUP = "group";
|
||||
static final String IS_OP = "operator";
|
||||
static final String CAN_FLY = "can-fly";
|
||||
static final String WALK_SPEED = "walk-speed";
|
||||
static final String FLY_SPEED = "fly-speed";
|
||||
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(LimboPlayer limboPlayer, Type type, JsonSerializationContext context) {
|
||||
Location loc = limboPlayer.getLocation();
|
||||
JsonObject locationObject = new JsonObject();
|
||||
locationObject.addProperty(LOC_WORLD, loc.getWorld().getName());
|
||||
locationObject.addProperty(LOC_X, loc.getX());
|
||||
locationObject.addProperty(LOC_Y, loc.getY());
|
||||
locationObject.addProperty(LOC_Z, loc.getZ());
|
||||
locationObject.addProperty(LOC_YAW, loc.getYaw());
|
||||
locationObject.addProperty(LOC_PITCH, loc.getPitch());
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add(LOCATION, locationObject);
|
||||
obj.addProperty(GROUP, limboPlayer.getGroup());
|
||||
obj.addProperty(IS_OP, limboPlayer.isOperator());
|
||||
obj.addProperty(CAN_FLY, limboPlayer.isCanFly());
|
||||
obj.addProperty(WALK_SPEED, limboPlayer.getWalkSpeed());
|
||||
obj.addProperty(FLY_SPEED, limboPlayer.getFlySpeed());
|
||||
return obj;
|
||||
}
|
||||
}
|
@ -3,26 +3,17 @@ package fr.xephi.authme.data.limbo.persistence;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.initialization.DataFolder;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.util.FileUtils;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
@ -32,19 +23,16 @@ class SeparateFilePersistenceHandler implements LimboPersistenceHandler {
|
||||
|
||||
private final Gson gson;
|
||||
private final File cacheDir;
|
||||
private final BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
SeparateFilePersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService) {
|
||||
this.bukkitService = bukkitService;
|
||||
|
||||
cacheDir = new File(dataFolder, "playerdata");
|
||||
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
|
||||
ConsoleLogger.warning("Failed to create userdata directory.");
|
||||
ConsoleLogger.warning("Failed to create playerdata directory '" + cacheDir + "'");
|
||||
}
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer())
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService))
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
}
|
||||
@ -99,80 +87,4 @@ class SeparateFilePersistenceHandler implements LimboPersistenceHandler {
|
||||
public LimboPersistenceType getType() {
|
||||
return LimboPersistenceType.INDIVIDUAL_FILES;
|
||||
}
|
||||
|
||||
private final class LimboPlayerDeserializer implements JsonDeserializer<LimboPlayer> {
|
||||
|
||||
@Override
|
||||
public LimboPlayer deserialize(JsonElement jsonElement, Type type,
|
||||
JsonDeserializationContext context) {
|
||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||
if (jsonObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Location loc = null;
|
||||
String group = "";
|
||||
boolean operator = false;
|
||||
boolean canFly = false;
|
||||
float walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
||||
float flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
||||
|
||||
JsonElement e;
|
||||
if ((e = jsonObject.getAsJsonObject("location")) != null) {
|
||||
JsonObject obj = e.getAsJsonObject();
|
||||
World world = bukkitService.getWorld(obj.get("world").getAsString());
|
||||
if (world != null) {
|
||||
double x = obj.get("x").getAsDouble();
|
||||
double y = obj.get("y").getAsDouble();
|
||||
double z = obj.get("z").getAsDouble();
|
||||
float yaw = obj.get("yaw").getAsFloat();
|
||||
float pitch = obj.get("pitch").getAsFloat();
|
||||
loc = new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
}
|
||||
if ((e = jsonObject.get("group")) != null) {
|
||||
group = e.getAsString();
|
||||
}
|
||||
if ((e = jsonObject.get("operator")) != null) {
|
||||
operator = e.getAsBoolean();
|
||||
}
|
||||
if ((e = jsonObject.get("can-fly")) != null) {
|
||||
canFly = e.getAsBoolean();
|
||||
}
|
||||
if ((e = jsonObject.get("walk-speed")) != null) {
|
||||
walkSpeed = e.getAsFloat();
|
||||
}
|
||||
if ((e = jsonObject.get("fly-speed")) != null) {
|
||||
flySpeed = e.getAsFloat();
|
||||
}
|
||||
|
||||
return new LimboPlayer(loc, operator, group, canFly, walkSpeed, flySpeed);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LimboPlayerSerializer implements JsonSerializer<LimboPlayer> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(LimboPlayer limboPlayer, Type type,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("group", limboPlayer.getGroup());
|
||||
|
||||
Location loc = limboPlayer.getLocation();
|
||||
JsonObject obj2 = new JsonObject();
|
||||
obj2.addProperty("world", loc.getWorld().getName());
|
||||
obj2.addProperty("x", loc.getX());
|
||||
obj2.addProperty("y", loc.getY());
|
||||
obj2.addProperty("z", loc.getZ());
|
||||
obj2.addProperty("yaw", loc.getYaw());
|
||||
obj2.addProperty("pitch", loc.getPitch());
|
||||
obj.add("location", obj2);
|
||||
|
||||
obj.addProperty("operator", limboPlayer.isOperator());
|
||||
obj.addProperty("can-fly", limboPlayer.isCanFly());
|
||||
obj.addProperty("walk-speed", limboPlayer.getWalkSpeed());
|
||||
obj.addProperty("fly-speed", limboPlayer.getFlySpeed());
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
package fr.xephi.authme.data.limbo.persistence;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.initialization.DataFolder;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.util.FileUtils;
|
||||
import fr.xephi.authme.util.PlayerUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Saves all LimboPlayers in one JSON file and keeps the entries in memory.
|
||||
*/
|
||||
class SingleFilePersistenceHandler implements LimboPersistenceHandler {
|
||||
|
||||
private final File cacheFile;
|
||||
private final Gson gson;
|
||||
private Map<String, LimboPlayer> entries;
|
||||
|
||||
@Inject
|
||||
SingleFilePersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService) {
|
||||
cacheFile = new File(dataFolder, "limbo.json");
|
||||
if (!cacheFile.exists()) {
|
||||
FileUtils.create(cacheFile);
|
||||
}
|
||||
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer(bukkitService))
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
Type type = new TypeToken<ConcurrentMap<String, LimboPlayer>>(){}.getType();
|
||||
try (FileReader fr = new FileReader(cacheFile)) {
|
||||
entries = gson.fromJson(fr, type);
|
||||
} catch (IOException e) {
|
||||
ConsoleLogger.logException("Failed to read from '" + cacheFile + "':", e);
|
||||
}
|
||||
|
||||
if (entries == null) {
|
||||
entries = new ConcurrentHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimboPlayer getLimboPlayer(Player player) {
|
||||
return entries.get(PlayerUtils.getUUIDorName(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLimboPlayer(Player player, LimboPlayer limbo) {
|
||||
entries.put(PlayerUtils.getUUIDorName(player), limbo);
|
||||
saveEntries("adding '" + player.getName() + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLimboPlayer(Player player) {
|
||||
LimboPlayer entry = entries.remove(PlayerUtils.getUUIDorName(player));
|
||||
if (entry != null) {
|
||||
saveEntries("removing '" + player.getName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the entries to the disk.
|
||||
*
|
||||
* @param action the reason for saving (for logging purposes)
|
||||
*/
|
||||
private void saveEntries(String action) {
|
||||
try (FileWriter fw = new FileWriter(cacheFile)) {
|
||||
gson.toJson(entries, fw);
|
||||
} catch (IOException e) {
|
||||
ConsoleLogger.logException("Failed saving JSON limbo cache after " + action, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimboPersistenceType getType() {
|
||||
return LimboPersistenceType.SINGLE_FILE;
|
||||
}
|
||||
}
|
@ -22,10 +22,11 @@ public final class LimboSettings implements SettingsHolder {
|
||||
"Besides storing the data in memory, you can define if/how the data should be persisted",
|
||||
"on disk. This is useful in case of a server crash, so next time the server starts we can",
|
||||
"properly restore things like OP status, ability to fly, and walk/fly speed.",
|
||||
"DISABLED: no disk storage, INDIVIDUAL_FILES: each player data in its own file"
|
||||
"DISABLED: no disk storage, INDIVIDUAL_FILES: each player data in its own file,",
|
||||
"SINGLE_FILE: all data in one single file (only if you have a small server!)"
|
||||
})
|
||||
public static final Property<LimboPersistenceType> LIMBO_PERSISTENCE_TYPE =
|
||||
newProperty(LimboPersistenceType.class, "limbo.persistence", LimboPersistenceType.INDIVIDUAL_FILES);
|
||||
newProperty(LimboPersistenceType.class, "limbo.persistence.type", LimboPersistenceType.INDIVIDUAL_FILES);
|
||||
|
||||
@Comment({
|
||||
"Whether the player is allowed to fly: RESTORE, ENABLE, DISABLE.",
|
||||
|
Loading…
Reference in New Issue
Block a user