Sponge support
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import lombok.Getter;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.implementation.ApiProvider;
|
||||
import me.lucko.luckperms.data.Datastore;
|
||||
import me.lucko.luckperms.data.methods.FlatfileDatastore;
|
||||
import me.lucko.luckperms.data.methods.MySQLDatastore;
|
||||
import me.lucko.luckperms.data.methods.SQLiteDatastore;
|
||||
import me.lucko.luckperms.groups.GroupManager;
|
||||
import me.lucko.luckperms.listeners.PlayerListener;
|
||||
import me.lucko.luckperms.runnables.UpdateTask;
|
||||
import me.lucko.luckperms.tracks.TrackManager;
|
||||
import me.lucko.luckperms.users.SpongeUserManager;
|
||||
import me.lucko.luckperms.users.UserManager;
|
||||
import me.lucko.luckperms.utils.LPConfiguration;
|
||||
import me.lucko.luckperms.utils.LogUtil;
|
||||
import me.lucko.luckperms.utils.UuidCache;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.api.Game;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandManager;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
|
||||
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import org.spongepowered.api.scheduler.Scheduler;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
@Plugin(id = "luckperms", name = "LuckPerms", version = LPSpongePlugin.VERSION)
|
||||
public class LPSpongePlugin implements LuckPermsPlugin {
|
||||
static final String VERSION = "1.5"; // TODO load this from pom
|
||||
|
||||
@Inject
|
||||
private Logger logger;
|
||||
|
||||
@Inject
|
||||
private Game game;
|
||||
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
private Path configDir;
|
||||
|
||||
private Scheduler scheduler = Sponge.getScheduler();
|
||||
|
||||
private LPConfiguration configuration;
|
||||
private UserManager userManager;
|
||||
private GroupManager groupManager;
|
||||
private TrackManager trackManager;
|
||||
private Datastore datastore;
|
||||
private UuidCache uuidCache;
|
||||
|
||||
@Listener
|
||||
public void onEnable(GamePreInitializationEvent event) {
|
||||
getLog().info("Loading configuration...");
|
||||
configuration = new SpongeConfig(this);
|
||||
|
||||
// register events
|
||||
Sponge.getEventManager().registerListeners(this, new PlayerListener(this));
|
||||
|
||||
// register commands
|
||||
getLog().info("Registering commands...");
|
||||
CommandManager cmdService = Sponge.getCommandManager();
|
||||
cmdService.register(this, new SpongeCommand(this), "luckperms", "perms", "lp", "permissions", "p", "perm");
|
||||
|
||||
getLog().info("Detecting storage method...");
|
||||
final String storageMethod = configuration.getStorageMethod();
|
||||
if (storageMethod.equalsIgnoreCase("mysql")) {
|
||||
getLog().info("Using MySQL as storage method.");
|
||||
datastore = new MySQLDatastore(this, configuration.getDatabaseValues());
|
||||
} else if (storageMethod.equalsIgnoreCase("sqlite")) {
|
||||
getLog().info("Using SQLite as storage method.");
|
||||
datastore = new SQLiteDatastore(this, new File(getStorageDir(), "luckperms.sqlite"));
|
||||
} else if (storageMethod.equalsIgnoreCase("flatfile")) {
|
||||
getLog().info("Using Flatfile (JSON) as storage method.");
|
||||
datastore = new FlatfileDatastore(this, getStorageDir());
|
||||
} else {
|
||||
getLog().severe("Storage method '" + storageMethod + "' was not recognised. Using SQLite as fallback.");
|
||||
datastore = new SQLiteDatastore(this, new File(getStorageDir(), "luckperms.sqlite"));
|
||||
}
|
||||
|
||||
getLog().info("Initialising datastore...");
|
||||
datastore.init();
|
||||
|
||||
getLog().info("Loading internal permission managers...");
|
||||
uuidCache = new UuidCache(getConfiguration().getOnlineMode());
|
||||
userManager = new SpongeUserManager(this);
|
||||
groupManager = new GroupManager(this);
|
||||
trackManager = new TrackManager();
|
||||
|
||||
// Run update task to refresh any online users
|
||||
getLog().info("Scheduling Update Task to refresh any online users.");
|
||||
try {
|
||||
new UpdateTask(this).run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int mins = getConfiguration().getSyncTime();
|
||||
if (mins > 0) {
|
||||
scheduler.createTaskBuilder().async().interval(mins, TimeUnit.MINUTES).execute(new UpdateTask(this))
|
||||
.submit(LPSpongePlugin.this);
|
||||
}
|
||||
|
||||
getLog().info("Registering API...");
|
||||
final ApiProvider provider = new ApiProvider(this);
|
||||
LuckPerms.registerProvider(provider);
|
||||
Sponge.getServiceManager().setProvider(this, LuckPermsApi.class, provider);
|
||||
|
||||
getLog().info("Successfully loaded.");
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onDisable(GameStoppingServerEvent event) {
|
||||
getLog().info("Closing datastore...");
|
||||
datastore.shutdown();
|
||||
|
||||
getLog().info("Unregistering API...");
|
||||
LuckPerms.unregisterProvider();
|
||||
}
|
||||
|
||||
private File getStorageDir() {
|
||||
File base = configDir.toFile().getParentFile().getParentFile();
|
||||
File luckperms = new File(base, "luckperms");
|
||||
luckperms.mkdirs();
|
||||
return luckperms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Logger getLog() {
|
||||
return LogUtil.wrap(getLogger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerStatus(UUID uuid) {
|
||||
return game.getServer().getPlayer(getUuidCache().getExternalUUID(uuid)).isPresent() ? "&aOnline" : "&cOffline";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
return game.getServer().getOnlinePlayers().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPlayerList() {
|
||||
return game.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runUpdateTask() {
|
||||
scheduler.createTaskBuilder().async().execute(new UpdateTask(this)).submit(LPSpongePlugin.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAsync(Runnable r) {
|
||||
scheduler.createTaskBuilder().async().execute(r).submit(LPSpongePlugin.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSync(Runnable r) {
|
||||
scheduler.createTaskBuilder().execute(r).submit(LPSpongePlugin.this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import me.lucko.luckperms.commands.CommandManager;
|
||||
import me.lucko.luckperms.commands.Sender;
|
||||
import me.lucko.luckperms.utils.Patterns;
|
||||
import org.spongepowered.api.command.CommandCallable;
|
||||
import org.spongepowered.api.command.CommandException;
|
||||
import org.spongepowered.api.command.CommandResult;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.text.Text;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SpongeCommand extends CommandManager implements CommandCallable {
|
||||
public SpongeCommand(LuckPermsPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult process(CommandSource source, String s) throws CommandException {
|
||||
onCommand(makeSender(source), "perms", Arrays.asList(Patterns.SPACE_SPLIT.split(s)));
|
||||
return CommandResult.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandSource source, String s) throws CommandException {
|
||||
return onTabComplete(makeSender(source), Arrays.asList(Patterns.SPACE_SPLIT.split(s)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandSource commandSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends Text> getShortDescription(CommandSource commandSource) {
|
||||
return Optional.of(Text.of("LuckPerms main command."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<? extends Text> getHelp(CommandSource commandSource) {
|
||||
return Optional.of(Text.of("Type /perms for help."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getUsage(CommandSource commandSource) {
|
||||
return Text.of("/perms");
|
||||
}
|
||||
|
||||
private static Sender makeSender(CommandSource source) {
|
||||
return new Sender() {
|
||||
final WeakReference<CommandSource> cs = new WeakReference<>(source);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void sendMessage(String s) {
|
||||
final CommandSource c = cs.get();
|
||||
if (c != null) {
|
||||
c.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(s));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String node) {
|
||||
final CommandSource c = cs.get();
|
||||
return c != null && c.hasPermission(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package me.lucko.luckperms;
|
||||
|
||||
import me.lucko.luckperms.utils.LPConfiguration;
|
||||
import ninja.leaping.configurate.ConfigurationNode;
|
||||
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
class SpongeConfig extends LPConfiguration<LPSpongePlugin> {
|
||||
private ConfigurationNode root;
|
||||
|
||||
SpongeConfig(LPSpongePlugin plugin) {
|
||||
super(plugin, "global", true, "sqlite");
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private Path makeFile(Path file) throws IOException {
|
||||
File cfg = file.toFile();
|
||||
cfg.getParentFile().mkdirs();
|
||||
|
||||
if (!cfg.exists()) {
|
||||
try (InputStream is = getPlugin().getClass().getClassLoader().getResourceAsStream("luckperms.conf")) {
|
||||
Files.copy(is, cfg.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
return cfg.toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
try {
|
||||
ConfigurationLoader<CommentedConfigurationNode> loader = HoconConfigurationLoader.builder()
|
||||
.setPath(makeFile(getPlugin().getConfigDir().resolve("luckperms.conf")))
|
||||
.build();
|
||||
|
||||
root = loader.load();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigurationNode getNode(String path) {
|
||||
String[] paths = path.split("\\.");
|
||||
ConfigurationNode node = root;
|
||||
|
||||
for (String s : paths) {
|
||||
node = node.getNode(s);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void set(String path, Object value) {
|
||||
getNode(path).setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getString(String path, String def) {
|
||||
return getNode(path).getString(def);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getInt(String path, int def) {
|
||||
return getNode(path).getInt(def);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getBoolean(String path, boolean def) {
|
||||
return getNode(path).getBoolean(def);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package me.lucko.luckperms.listeners;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.lucko.luckperms.LPSpongePlugin;
|
||||
import me.lucko.luckperms.commands.Util;
|
||||
import me.lucko.luckperms.constants.Message;
|
||||
import me.lucko.luckperms.users.User;
|
||||
import me.lucko.luckperms.utils.UuidCache;
|
||||
import org.spongepowered.api.entity.Entity;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.entity.DisplaceEntityEvent;
|
||||
import org.spongepowered.api.event.network.ClientConnectionEvent;
|
||||
import org.spongepowered.api.profile.GameProfile;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class PlayerListener {
|
||||
private static final String KICK_MESSAGE = Util.color(Message.PREFIX + "User data could not be loaded. Please contact an administrator.");
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
@Listener
|
||||
public void onClientAuth(ClientConnectionEvent.Auth e) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
if (!plugin.getDatastore().isAcceptingLogins()) {
|
||||
// Datastore is disabled, prevent players from joining the server
|
||||
// Just don't load their data, they will be kickec at login
|
||||
return;
|
||||
}
|
||||
|
||||
final UuidCache cache = plugin.getUuidCache();
|
||||
final GameProfile p = e.getProfile();
|
||||
final String name = p.getName().get();
|
||||
|
||||
if (!cache.isOnlineMode()) {
|
||||
UUID uuid = plugin.getDatastore().getUUID(name);
|
||||
if (uuid != null) {
|
||||
cache.addToCache(p.getUniqueId(), uuid);
|
||||
} else {
|
||||
// No previous data for this player
|
||||
cache.addToCache(p.getUniqueId(), p.getUniqueId());
|
||||
plugin.getDatastore().saveUUIDData(name, p.getUniqueId(), b -> {});
|
||||
}
|
||||
} else {
|
||||
// Online mode, no cache needed. This is just for name -> uuid lookup.
|
||||
plugin.getDatastore().saveUUIDData(name, p.getUniqueId(), b -> {});
|
||||
}
|
||||
|
||||
plugin.getDatastore().loadOrCreateUser(cache.getUUID(p.getUniqueId()), name);
|
||||
final long time = System.currentTimeMillis() - startTime;
|
||||
if (time >= 1000) {
|
||||
plugin.getLog().warn("Processing login for " + p.getName() + " took " + time + "ms.");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Listener
|
||||
public void onClientLogin(ClientConnectionEvent.Login e) {
|
||||
final GameProfile player = e.getProfile();
|
||||
final User user = plugin.getUserManager().getUser(plugin.getUuidCache().getUUID(player.getUniqueId()));
|
||||
|
||||
if (user == null) {
|
||||
e.setCancelled(true);
|
||||
e.setMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(KICK_MESSAGE));
|
||||
return;
|
||||
}
|
||||
|
||||
user.refreshPermissions();
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onClientJoin(ClientConnectionEvent.Join e) {
|
||||
// Refresh permissions again
|
||||
refreshPlayer(e.getTargetEntity());
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onPlayerTeleport(DisplaceEntityEvent.Teleport e) {
|
||||
final Entity entity = e.getTargetEntity();
|
||||
if (!(entity instanceof Player)){
|
||||
return;
|
||||
}
|
||||
|
||||
refreshPlayer((Player) entity);
|
||||
}
|
||||
|
||||
@Listener
|
||||
public void onClientLeave(ClientConnectionEvent.Disconnect e) {
|
||||
final Player player = e.getTargetEntity();
|
||||
final UuidCache cache = plugin.getUuidCache();
|
||||
|
||||
// Unload the user from memory when they disconnect;
|
||||
cache.clearCache(player.getUniqueId());
|
||||
|
||||
final User user = plugin.getUserManager().getUser(cache.getUUID(player.getUniqueId()));
|
||||
plugin.getUserManager().unloadUser(user);
|
||||
}
|
||||
|
||||
private void refreshPlayer(Player p) {
|
||||
final User user = plugin.getUserManager().getUser(plugin.getUuidCache().getUUID(p.getUniqueId()));
|
||||
if (user != null) {
|
||||
user.refreshPermissions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package me.lucko.luckperms.users;
|
||||
|
||||
import me.lucko.luckperms.LPSpongePlugin;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
class SpongeUser extends User {
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
SpongeUser(UUID uuid, LPSpongePlugin plugin) {
|
||||
super(uuid, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
SpongeUser(UUID uuid, String username, LPSpongePlugin plugin) {
|
||||
super(uuid, username, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshPermissions() {
|
||||
Optional<Player> p = plugin.getGame().getServer().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
|
||||
if (!p.isPresent()) return;
|
||||
|
||||
final Player player = p.get();
|
||||
|
||||
// Clear existing permissions
|
||||
player.getSubjectData().clearParents();
|
||||
player.getSubjectData().clearPermissions();
|
||||
|
||||
// Re-add all defined permissions for the user
|
||||
final String world = player.getWorld().getName();
|
||||
Map<String, Boolean> local = getLocalPermissions(getPlugin().getConfiguration().getServer(), world, null);
|
||||
local.entrySet().forEach(e -> player.getSubjectData().setPermission(new HashSet<>(), e.getKey(), Tristate.fromBoolean(e.getValue())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package me.lucko.luckperms.users;
|
||||
|
||||
import me.lucko.luckperms.LPSpongePlugin;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpongeUserManager extends UserManager {
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
public SpongeUserManager(LPSpongePlugin plugin) {
|
||||
super(plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadUser(User user) {
|
||||
if (user != null) {
|
||||
Optional<Player> p = plugin.getGame().getServer().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid()));
|
||||
if (p.isPresent()) {
|
||||
p.get().getSubjectData().clearParents();
|
||||
p.get().getSubjectData().clearPermissions();
|
||||
}
|
||||
getUsers().remove(user.getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanupUser(User user) {
|
||||
if (plugin.getGame().getServer().getPlayer(plugin.getUuidCache().getExternalUUID(user.getUuid())).isPresent()) {
|
||||
unloadUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public User makeUser(UUID uuid) {
|
||||
return new SpongeUser(uuid, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User makeUser(UUID uuid, String username) {
|
||||
return new SpongeUser(uuid, username, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAllUsers() {
|
||||
plugin.getGame().getServer().getOnlinePlayers().stream()
|
||||
.map(p -> plugin.getUuidCache().getUUID(p.getUniqueId()))
|
||||
.forEach(u -> plugin.getDatastore().loadUser(u));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user