#1113 Handle LimboPlayers within LimboService (remove LimboCache) (work in progress)
- Delete LimboCache and LimboPlayerStorage: LimboService now handles all LimboPlayer actions - Revoke player rights when creating a LimboPlayer, within the LimboService - Various fixes and improvements
This commit is contained in:
@@ -1,151 +0,0 @@
|
||||
package fr.xephi.authme.data.limbo;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.settings.SpawnLoader;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Manages all {@link LimboPlayer} instances.
|
||||
*/
|
||||
class LimboCache {
|
||||
|
||||
private final Map<String, LimboPlayer> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private LimboPlayerStorage limboPlayerStorage;
|
||||
private PermissionsManager permissionsManager;
|
||||
private SpawnLoader spawnLoader;
|
||||
|
||||
@Inject
|
||||
LimboCache(PermissionsManager permissionsManager, SpawnLoader spawnLoader, LimboPlayerStorage limboPlayerStorage) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
this.spawnLoader = spawnLoader;
|
||||
this.limboPlayerStorage = limboPlayerStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load player data if exist, otherwise current player's data will be stored.
|
||||
*
|
||||
* @param player Player instance to add.
|
||||
*/
|
||||
public void addPlayerData(Player player) {
|
||||
String name = player.getName().toLowerCase();
|
||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||
boolean operator = player.isOp();
|
||||
boolean flyEnabled = player.getAllowFlight();
|
||||
float walkSpeed = player.getWalkSpeed();
|
||||
float flySpeed = player.getFlySpeed();
|
||||
String playerGroup = "";
|
||||
if (permissionsManager.hasGroupSupport()) {
|
||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
||||
}
|
||||
ConsoleLogger.debug("Player `{0}` has primary group `{1}`", player.getName(), playerGroup);
|
||||
|
||||
if (limboPlayerStorage.hasData(player)) {
|
||||
LimboPlayer cache = limboPlayerStorage.readData(player);
|
||||
if (cache != null) {
|
||||
location = cache.getLocation();
|
||||
playerGroup = cache.getGroup();
|
||||
operator = cache.isOperator();
|
||||
flyEnabled = cache.isCanFly();
|
||||
walkSpeed = cache.getWalkSpeed();
|
||||
flySpeed = cache.getFlySpeed();
|
||||
}
|
||||
} else {
|
||||
limboPlayerStorage.saveData(player);
|
||||
}
|
||||
|
||||
cache.put(name, new LimboPlayer(location, operator, playerGroup, flyEnabled, walkSpeed, flySpeed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore player's data to player if exist.
|
||||
*
|
||||
* @param player Player instance to restore
|
||||
*/
|
||||
public void restoreData(Player player) {
|
||||
String lowerName = player.getName().toLowerCase();
|
||||
if (cache.containsKey(lowerName)) {
|
||||
LimboPlayer data = cache.get(lowerName);
|
||||
player.setOp(data.isOperator());
|
||||
player.setAllowFlight(data.isCanFly());
|
||||
float walkSpeed = data.getWalkSpeed();
|
||||
float flySpeed = data.getFlySpeed();
|
||||
// Reset the speed value if it was 0
|
||||
if (walkSpeed < 0.01f) {
|
||||
walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
||||
}
|
||||
if (flySpeed < 0.01f) {
|
||||
flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
||||
}
|
||||
player.setWalkSpeed(walkSpeed);
|
||||
player.setFlySpeed(flySpeed);
|
||||
data.clearTasks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PlayerData from cache and disk.
|
||||
*
|
||||
* @param player Player player to remove.
|
||||
*/
|
||||
public void deletePlayerData(Player player) {
|
||||
removeFromCache(player);
|
||||
limboPlayerStorage.removeData(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PlayerData from cache.
|
||||
*
|
||||
* @param player player to remove.
|
||||
*/
|
||||
public void removeFromCache(Player player) {
|
||||
String name = player.getName().toLowerCase();
|
||||
LimboPlayer cachedPlayer = cache.remove(name);
|
||||
if (cachedPlayer != null) {
|
||||
cachedPlayer.clearTasks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method getPlayerData.
|
||||
*
|
||||
* @param name String
|
||||
*
|
||||
* @return PlayerData
|
||||
*/
|
||||
public LimboPlayer getPlayerData(String name) {
|
||||
checkNotNull(name);
|
||||
return cache.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method hasPlayerData.
|
||||
*
|
||||
* @param name String
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean hasPlayerData(String name) {
|
||||
checkNotNull(name);
|
||||
return cache.containsKey(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method updatePlayerData.
|
||||
*
|
||||
* @param player Player
|
||||
*/
|
||||
public void updatePlayerData(Player player) {
|
||||
checkNotNull(player);
|
||||
removeFromCache(player);
|
||||
addPlayerData(player);
|
||||
}
|
||||
}
|
||||
@@ -118,13 +118,7 @@ public class LimboPlayer {
|
||||
* Clears all tasks associated to the player.
|
||||
*/
|
||||
public void clearTasks() {
|
||||
if (messageTask != null) {
|
||||
messageTask.cancel();
|
||||
}
|
||||
messageTask = null;
|
||||
if (timeoutTask != null) {
|
||||
timeoutTask.cancel();
|
||||
}
|
||||
timeoutTask = null;
|
||||
setMessageTask(null);
|
||||
setTimeoutTask(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
package fr.xephi.authme.data.limbo;
|
||||
|
||||
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.initialization.DataFolder;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.SpawnLoader;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class used to store player's data (OP, flying, speed, position) to disk.
|
||||
*/
|
||||
class LimboPlayerStorage {
|
||||
|
||||
private final Gson gson;
|
||||
private final File cacheDir;
|
||||
private PermissionsManager permissionsManager;
|
||||
private SpawnLoader spawnLoader;
|
||||
private BukkitService bukkitService;
|
||||
|
||||
@Inject
|
||||
LimboPlayerStorage(@DataFolder File dataFolder, PermissionsManager permsMan,
|
||||
SpawnLoader spawnLoader, BukkitService bukkitService) {
|
||||
this.permissionsManager = permsMan;
|
||||
this.spawnLoader = spawnLoader;
|
||||
this.bukkitService = bukkitService;
|
||||
|
||||
cacheDir = new File(dataFolder, "playerdata");
|
||||
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
|
||||
ConsoleLogger.warning("Failed to create userdata directory.");
|
||||
}
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerDeserializer())
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and construct new PlayerData from existing player data.
|
||||
*
|
||||
* @param player player to read
|
||||
*
|
||||
* @return PlayerData object if the data is exist, null otherwise.
|
||||
*/
|
||||
public LimboPlayer readData(Player player) {
|
||||
String id = PlayerUtils.getUUIDorName(player);
|
||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String str = Files.toString(file, StandardCharsets.UTF_8);
|
||||
return gson.fromJson(str, LimboPlayer.class);
|
||||
} catch (IOException e) {
|
||||
ConsoleLogger.logException("Could not read player data on disk for '" + player.getName() + "'", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save player data (OP, flying, location, etc) to disk.
|
||||
*
|
||||
* @param player player to save
|
||||
*/
|
||||
public void saveData(Player player) {
|
||||
String id = PlayerUtils.getUUIDorName(player);
|
||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||
String group = "";
|
||||
if (permissionsManager.hasGroupSupport()) {
|
||||
group = permissionsManager.getPrimaryGroup(player);
|
||||
}
|
||||
boolean operator = player.isOp();
|
||||
boolean canFly = player.getAllowFlight();
|
||||
float walkSpeed = player.getWalkSpeed();
|
||||
float flySpeed = player.getFlySpeed();
|
||||
LimboPlayer limboPlayer = new LimboPlayer(location, operator, group, canFly, walkSpeed, flySpeed);
|
||||
try {
|
||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||
Files.createParentDirs(file);
|
||||
Files.touch(file);
|
||||
Files.write(gson.toJson(limboPlayer), file, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
ConsoleLogger.logException("Failed to write " + player.getName() + " data.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove player data, this will delete
|
||||
* "playerdata/<uuid or name>/" folder from disk.
|
||||
*
|
||||
* @param player player to remove
|
||||
*/
|
||||
public void removeData(Player player) {
|
||||
String id = PlayerUtils.getUUIDorName(player);
|
||||
File file = new File(cacheDir, id);
|
||||
if (file.exists()) {
|
||||
FileUtils.purgeDirectory(file);
|
||||
if (!file.delete()) {
|
||||
ConsoleLogger.warning("Failed to remove " + player.getName() + " cache.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to check is player data is exist.
|
||||
*
|
||||
* @param player player to check
|
||||
*
|
||||
* @return true if data exist, false otherwise.
|
||||
*/
|
||||
public boolean hasData(Player player) {
|
||||
String id = PlayerUtils.getUUIDorName(player);
|
||||
File file = new File(cacheDir, id + File.separator + "data.json");
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
private 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
package fr.xephi.authme.data.limbo;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.SpawnLoader;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Service for managing players that are in "limbo," a temporary state players are
|
||||
@@ -10,8 +18,16 @@ import javax.inject.Inject;
|
||||
*/
|
||||
public class LimboService {
|
||||
|
||||
private Map<String, LimboPlayer> entries = new ConcurrentHashMap<>();
|
||||
|
||||
@Inject
|
||||
private LimboCache limboCache;
|
||||
private SpawnLoader spawnLoader;
|
||||
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
|
||||
@Inject
|
||||
private Settings settings;
|
||||
|
||||
LimboService() {
|
||||
}
|
||||
@@ -19,13 +35,34 @@ public class LimboService {
|
||||
|
||||
/**
|
||||
* Restores the limbo data and subsequently deletes the entry.
|
||||
* <p>
|
||||
* Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and
|
||||
* changing the permission group is handled by {@link fr.xephi.authme.permission.AuthGroupHandler}.
|
||||
*
|
||||
* @param player the player whose data should be restored
|
||||
*/
|
||||
public void restoreData(Player player) {
|
||||
// TODO #1113: Think about architecture for various "restore" strategies
|
||||
limboCache.restoreData(player);
|
||||
limboCache.deletePlayerData(player);
|
||||
String lowerName = player.getName().toLowerCase();
|
||||
LimboPlayer limbo = entries.remove(lowerName);
|
||||
|
||||
if (limbo == null) {
|
||||
ConsoleLogger.debug("No LimboPlayer found for `{0}` - cannot restore", lowerName);
|
||||
} else {
|
||||
player.setOp(limbo.isOperator());
|
||||
player.setAllowFlight(limbo.isCanFly());
|
||||
float walkSpeed = limbo.getWalkSpeed();
|
||||
float flySpeed = limbo.getFlySpeed();
|
||||
// Reset the speed value if it was 0
|
||||
if (walkSpeed < 0.01f) {
|
||||
walkSpeed = LimboPlayer.DEFAULT_WALK_SPEED;
|
||||
}
|
||||
if (flySpeed < 0.01f) {
|
||||
flySpeed = LimboPlayer.DEFAULT_FLY_SPEED;
|
||||
}
|
||||
player.setWalkSpeed(walkSpeed);
|
||||
player.setFlySpeed(flySpeed);
|
||||
limbo.clearTasks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +72,7 @@ public class LimboService {
|
||||
* @return the associated limbo player, or null if none available
|
||||
*/
|
||||
public LimboPlayer getLimboPlayer(String name) {
|
||||
return limboCache.getPlayerData(name);
|
||||
return entries.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,16 +82,65 @@ public class LimboService {
|
||||
* @return true if present, false otherwise
|
||||
*/
|
||||
public boolean hasLimboPlayer(String name) {
|
||||
return limboCache.hasPlayerData(name);
|
||||
return entries.containsKey(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LimboPlayer for the given player.
|
||||
* Creates a LimboPlayer for the given player and revokes all "limbo data" from the player.
|
||||
*
|
||||
* @param player the player to process
|
||||
*/
|
||||
public void createLimboPlayer(Player player) {
|
||||
// TODO #1113: We should remove the player's data in here as well
|
||||
limboCache.addPlayerData(player);
|
||||
final String name = player.getName().toLowerCase();
|
||||
|
||||
LimboPlayer existingLimbo = entries.remove(name);
|
||||
if (existingLimbo != null) {
|
||||
existingLimbo.clearTasks();
|
||||
ConsoleLogger.debug("LimboPlayer for `{0}` was already present", name);
|
||||
}
|
||||
|
||||
LimboPlayer limboPlayer = newLimboPlayer(player);
|
||||
revokeLimboStates(player);
|
||||
entries.put(name, limboPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LimboPlayer with the given player's details.
|
||||
*
|
||||
* @param player the player to process
|
||||
* @return limbo player with the player's data
|
||||
*/
|
||||
private LimboPlayer newLimboPlayer(Player player) {
|
||||
Location location = spawnLoader.getPlayerLocationOrSpawn(player);
|
||||
boolean isOperator = player.isOp();
|
||||
boolean flyEnabled = player.getAllowFlight();
|
||||
float walkSpeed = player.getWalkSpeed();
|
||||
float flySpeed = player.getFlySpeed();
|
||||
String playerGroup = "";
|
||||
if (permissionsManager.hasGroupSupport()) {
|
||||
playerGroup = permissionsManager.getPrimaryGroup(player);
|
||||
}
|
||||
ConsoleLogger.debug("Player `{0}` has primary group `{1}`", player.getName(), playerGroup);
|
||||
|
||||
return new LimboPlayer(location, isOperator, playerGroup, flyEnabled, walkSpeed, flySpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the data that is saved in a LimboPlayer from the player.
|
||||
* <p>
|
||||
* Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and
|
||||
* changing the permission group is handled by {@link fr.xephi.authme.permission.AuthGroupHandler}.
|
||||
*
|
||||
* @param player the player to set defaults to
|
||||
*/
|
||||
private void revokeLimboStates(Player player) {
|
||||
player.setOp(false);
|
||||
player.setAllowFlight(false);
|
||||
|
||||
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)
|
||||
&& settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
||||
player.setFlySpeed(0.0f);
|
||||
player.setWalkSpeed(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user