updates 🎱

This commit is contained in:
Paul Reilly
2023-05-30 17:39:54 -05:00
parent b95a06fa7c
commit def84bd747
63 changed files with 1469 additions and 1195 deletions

View File

@ -20,18 +20,40 @@ public class Datura extends JavaPlugin
public void onEnable()
{
CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.addModule(this);
.getRegistrations()
.getModuleRegistry()
.addModule(this);
CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, locker);
CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, cager);
CommonsBase.getInstance()
.getRegistrations()
.getServiceRegistry()
.register(this, locker);
CommonsBase.getInstance()
.getRegistrations()
.getServiceRegistry()
.register(this, cager);
Bukkit.getPluginManager().registerEvents(halter, this);
Bukkit.getPluginManager()
.registerEvents(halter, this);
}
public MySQL getSQL()
{
return sql;
}
public Halter getHalter()
{
return halter;
}
public Locker getLocker()
{
return locker;
}
public Cager getCager()
{
return cager;
}
}

View File

@ -1,66 +0,0 @@
package me.totalfreedom.datura.banning;
import me.totalfreedom.security.ban.BanID;
import java.time.Instant;
import java.time.temporal.ChronoField;
public final class BanUID implements BanID
{
private final char prefix;
private final int numericalTag;
private BanUID(final boolean permanent)
{
if (permanent)
{
prefix = 'P';
} else
{
prefix = 'T';
}
final Instant instant = Instant.now();
final String stringBuilder = String.valueOf(instant.get(ChronoField.DAY_OF_YEAR)) + // The first three numbers between 001 -> 365
instant.get(ChronoField.HOUR_OF_DAY) + // next two numbers between 00 -> 23
instant.get(ChronoField.MINUTE_OF_HOUR) + // next two numbers between 00 -> 59
instant.get(ChronoField.MILLI_OF_SECOND); // last three numbers between 000 -> 999
numericalTag = Integer.parseInt(stringBuilder);
}
public static BanUID createTempID()
{
return new BanUID(false);
}
public static BanUID createPermID()
{
return new BanUID(true);
}
@Override
public String getID()
{
return getIDPrefix() + "-" + getNumericalTag();
}
@Override
public char getIDPrefix()
{
return prefix;
}
@Override
public int getNumericalTag()
{
return numericalTag;
}
@Override
public boolean isPermanent()
{
return getIDPrefix() == 'P';
}
}

View File

@ -1,82 +0,0 @@
package me.totalfreedom.datura.banning;
import me.totalfreedom.security.ban.Ban;
import me.totalfreedom.security.ban.BanID;
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
import java.util.UUID;
public final class SimpleBan implements Ban
{
private final BanID id;
private final UUID offenderID;
private final String reason;
private final String issuer;
private final Instant creationTime;
private final Instant expiry;
public SimpleBan(
final UUID offenderID,
final String reason,
final String issuer,
final Instant creationTime,
final Instant expiry)
{
if (expiry == null)
{
this.id = BanUID.createPermID();
} else
{
this.id = BanUID.createTempID();
}
this.offenderID = offenderID;
this.reason = reason;
this.issuer = issuer;
this.creationTime = creationTime;
this.expiry = expiry;
}
@Override
public BanID getBanID()
{
return id;
}
@Override
public UUID getOffenderID()
{
return offenderID;
}
@Override
public String getReason()
{
return reason;
}
@Override
public String getBanIssuer()
{
return issuer;
}
@Override
public Instant getCreationTime()
{
return creationTime;
}
@Override
public @Nullable Instant getExpiry()
{
return expiry;
}
@Override
public boolean isExpired()
{
return Instant.now().compareTo(expiry) >= 0;
}
}

View File

@ -1,26 +0,0 @@
package me.totalfreedom.datura.cmd;
import me.totalfreedom.command.CommandBase;
import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Info;
import me.totalfreedom.command.annotation.Permissive;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.datura.Datura;
import org.bukkit.entity.Player;
@Completion(args = {"%player%"}, index = 0)
@Info(name = "kick", description = "Kick a player from the server.", usage = "/kick <player>")
@Permissive(perm = "datura.kick")
public class KickCommand extends CommandBase
{
protected KickCommand(final Datura plugin)
{
super(plugin);
}
@Subcommand(permission = "datura.kick", args = {Player.class})
public void kick(final Player player)
{
player.kickPlayer("You have been kicked from the server.");
}
}

View File

@ -0,0 +1,41 @@
package me.totalfreedom.datura.cmd;
import me.totalfreedom.command.Commander;
import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Info;
import me.totalfreedom.command.annotation.Permissive;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.datura.Datura;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@Info(name = "locker", description = "Lock a player, preventing them from interacting with their game client.",
usage = "/locker <player> <on|off>", aliases = {"lock", "lockup"})
@Permissive(perm = "datura.locker")
public final class LockerCommand extends Commander
{
public LockerCommand(final @NotNull Datura plugin)
{
super(plugin);
}
@Completion(args = {"%player%"}, index = 0)
@Completion(args = {"on", "off"}, index = 1)
@Subcommand(permission = "datura.locker", args = {Player.class, String.class})
public void lockPlayer(final CommandSender sender, final Player player, final String string)
{
if (string.equalsIgnoreCase("on"))
{
((Datura) getPlugin()).getLocker()
.lock(player);
sender.sendPlainMessage("Locked " + player.getName() + ".");
} else if (string.equalsIgnoreCase("off"))
{
((Datura) getPlugin()).getLocker()
.unlock(player);
sender.sendPlainMessage("Unlocked " + player.getName() + ".");
}
}
}

View File

@ -5,39 +5,37 @@ import me.totalfreedom.security.perm.NodeType;
public class DefaultNodes
{
private DefaultNodes() {
public static final Node OP = new PermissionNodeBuilder()
.key("freedom.master_key")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NON_OP = new PermissionNodeBuilder()
.key("freedom.default")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
public static final Node ALL = new PermissionNodeBuilder()
.key("*")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NONE = new PermissionNodeBuilder()
.key("freedom.none")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
private DefaultNodes()
{
throw new AssertionError();
}
public static final Node OP = new PermissionNodeBuilder()
.key("freedom.master_key")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NON_OP = new PermissionNodeBuilder()
.key("freedom.default")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
public static final Node ALL = new PermissionNodeBuilder()
.key("*")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(true)
.build();
public static final Node NONE = new PermissionNodeBuilder()
.key("freedom.none")
.value(true)
.type(NodeType.PERMISSION)
.negated(false)
.wildcard(false)
.build();
}

View File

@ -28,11 +28,11 @@ public class FreedomGroup implements Group
private final PermissionAttachment attachment;
public FreedomGroup(final Component name,
final Component prefix,
final Component abbreviation,
final int weight,
final boolean isDefault,
final boolean isHidden)
final Component prefix,
final Component abbreviation,
final int weight,
final boolean isDefault,
final boolean isHidden)
{
this.name = name;
this.prefix = prefix;
@ -44,6 +44,12 @@ public class FreedomGroup implements Group
this.attachment = new PermissionAttachment(CommonsBase.getInstance(), this);
}
@Override
public UUID getUniqueId()
{
return UUID.nameUUIDFromBytes(getName().toString()
.getBytes());
}
@Override
public Component getName()
@ -81,12 +87,6 @@ public class FreedomGroup implements Group
return isHidden;
}
@Override
public UUID getUniqueId()
{
return UUID.nameUUIDFromBytes(getName().toString().getBytes());
}
@Override
public Set<Node> permissions()
{
@ -109,9 +109,10 @@ public class FreedomGroup implements Group
public boolean isPermissionSet(@NotNull final String name)
{
final Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
.filter(n -> n.key()
.equalsIgnoreCase(name))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@ -120,10 +121,11 @@ public class FreedomGroup implements Group
public boolean isPermissionSet(@NotNull final Permission perm)
{
final Node node = permissions()
.stream()
.filter(n -> n.bukkit().equals(perm))
.findFirst()
.orElse(null);
.stream()
.filter(n -> n.bukkit()
.equals(perm))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@ -132,9 +134,10 @@ public class FreedomGroup implements Group
public boolean hasPermission(@NotNull final String name)
{
final Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
.filter(n -> n.key()
.equalsIgnoreCase(name))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@ -143,10 +146,11 @@ public class FreedomGroup implements Group
public boolean hasPermission(@NotNull final Permission perm)
{
final Node node = permissions()
.stream()
.filter(n -> n.bukkit().equals(perm))
.findFirst()
.orElse(null);
.stream()
.filter(n -> n.bukkit()
.equals(perm))
.findFirst()
.orElse(null);
return node != null && node.value();
}
@ -164,7 +168,8 @@ public class FreedomGroup implements Group
* @return This group's PermissionAttachment.
*/
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name, final boolean value)
public @NotNull PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name,
final boolean value)
{
attachment.setPermission(name, value);
return attachment;
@ -177,7 +182,8 @@ public class FreedomGroup implements Group
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name, final boolean value, final int ticks)
public @Nullable PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name,
final boolean value, final int ticks)
{
attachment.setPermission(name, value);
return attachment;
@ -205,23 +211,23 @@ public class FreedomGroup implements Group
public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions()
{
return permissions()
.stream()
.map(n -> new PermissionAttachmentInfo(
this,
n.key(),
attachment,
n.value()))
.collect(Collectors.toSet());
.stream()
.map(n -> new PermissionAttachmentInfo(
this,
n.key(),
attachment,
n.value()))
.collect(Collectors.toSet());
}
@Override
public boolean isOp()
{
final Node node = permissions()
.stream()
.filter(n -> n.equals(DefaultNodes.OP))
.findFirst()
.orElse(null);
.stream()
.filter(n -> n.equals(DefaultNodes.OP))
.findFirst()
.orElse(null);
return node != null && node.value();
}

View File

@ -43,10 +43,10 @@ public class FreedomUser implements User
this.displayName = player.displayName();
final Datura datura = CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.getModule(Datura.class)
.getModule();
.getRegistrations()
.getModuleRegistry()
.getModule(Datura.class)
.getModule();
UserData data = SimpleUserData.fromSQL(datura.getSQL(), uuid.toString());
@ -58,16 +58,29 @@ public class FreedomUser implements User
this.userData = data;
CommonsBase.getInstance()
.getRegistrations()
.getUserRegistry()
.registerUserData(this, userData);
.getRegistrations()
.getUserRegistry()
.registerUserData(this, userData);
}
@Override
public UserData getUserData() {
public UserData getUserData()
{
return userData;
}
@Override
public Component getDisplayName()
{
return displayName;
}
@Override
public boolean isOnline()
{
return Bukkit.getPlayer(uuid) != null;
}
@Override
public UUID getUniqueId()
{
@ -96,18 +109,6 @@ public class FreedomUser implements User
return permissions.remove(node);
}
@Override
public Component getDisplayName()
{
return displayName;
}
@Override
public boolean isOnline()
{
return Bukkit.getPlayer(uuid) != null;
}
@Override
public boolean isPermissionSet(@NotNull final String name)
{
@ -137,7 +138,8 @@ public class FreedomUser implements User
}
@Override
public @NotNull PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name, final boolean value)
public @NotNull PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name,
final boolean value)
{
final Player player = Bukkit.getPlayer(uuid);
if (player != null)
@ -161,7 +163,8 @@ public class FreedomUser implements User
}
@Override
public @Nullable PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name, final boolean value, final int ticks)
public @Nullable PermissionAttachment addAttachment(@NotNull final Plugin plugin, @NotNull final String name,
final boolean value, final int ticks)
{
final Player player = Bukkit.getPlayer(uuid);
if (player != null)

View File

@ -9,29 +9,31 @@ record PermissionNode(String key,
boolean value,
long expiry,
NodeType type,
boolean wildcard,
boolean negated) implements Node
boolean wildcard) implements Node
{
@Override
public Permission bukkit()
{
return new Permission(key(),
value() ? PermissionDefault.TRUE : PermissionDefault.FALSE);
value()
? PermissionDefault.TRUE
: PermissionDefault.FALSE);
}
@Override
public boolean compare(final Node node)
{
return node.key().equalsIgnoreCase(key())
&& node.value() == value()
&& node.type() == type();
return node.key()
.equalsIgnoreCase(key())
&& node.value() == value()
&& node.type() == type();
}
@Override
public boolean isExpired()
{
if (isPermanent())
if (!isTemporary())
{
return false;
}
@ -39,15 +41,9 @@ record PermissionNode(String key,
return System.currentTimeMillis() > expiry();
}
@Override
public boolean isPermanent()
{
return expiry() == -1;
}
@Override
public boolean isTemporary()
{
return !isPermanent();
return expiry() > -1;
}
}

View File

@ -14,8 +14,8 @@ import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@ -31,7 +31,8 @@ public class Cager extends Service
super("cage_service");
this.cagedPlayers = new HashSet<>();
this.cageLocations = new HashMap<>();
Bukkit.getPluginManager().registerEvents(new CageListener(), CommonsBase.getInstance());
Bukkit.getPluginManager()
.registerEvents(new CageListener(), CommonsBase.getInstance());
}
/**
@ -49,6 +50,39 @@ public class Cager extends Service
cageLocations.put(uuid, createCage(player.getLocation(), Material.GLASS));
}
/**
* This method generates a cube centered around the passed location,
* made of the provided material. This method returns the passed location object.
* We use the {@link Shaper} class to generate the cube, which allows us to define
* custom shapes using {@link DoubleUnaryOperator}s.
*
* @param location The location to center the cube around.
* @param material The material to use for the cube.
* @return The center location of the cube (the passed location).
* @see Shaper
* @see DoubleUnaryOperator
*/
public Location createCage(final Location location, final Material material)
{
final Shaper shaper = new Shaper(location.getWorld(), 0.0, 4.0);
final List<Location> cubed = new LinkedList<>();
cubed.addAll(shaper.generate(5, t -> t, t -> 4.0, t -> t));
cubed.addAll(shaper.generate(5, t -> t, t -> 0.0, t -> t));
cubed.addAll(shaper.generate(5, t -> 0.0, t -> t, t -> t));
cubed.addAll(shaper.generate(5, t -> 4.0, t -> t, t -> t));
cubed.addAll(shaper.generate(5, t -> t, t -> t, t -> 0.0));
cubed.addAll(shaper.generate(5, t -> t, t -> t, t -> 4.0));
for (final Location l : cubed)
{
location.getWorld()
.getBlockAt(l)
.setType(material);
}
return location.clone(); // Return the passed location as that is the center of the cube.
}
public void cagePlayer(final UUID uuid, final Material material)
{
final Player player = Bukkit.getPlayer(uuid);
@ -92,12 +126,14 @@ public class Cager extends Service
final Location cageLocation = getCageLocation(player);
final boolean inside;
if (!player.getWorld().equals(cageLocation.getWorld()))
if (!player.getWorld()
.equals(cageLocation.getWorld()))
{
inside = false;
} else
{
inside = player.getLocation().distanceSquared(cageLocation) > (Math.pow(2.5, 2.0));
inside = player.getLocation()
.distanceSquared(cageLocation) > (Math.pow(2.5, 2.0));
}
if (!inside)
@ -119,43 +155,13 @@ public class Cager extends Service
return cageLocations.get(player.getUniqueId());
}
/**
* This method generates a cube centered around the passed location,
* made of the provided material. This method returns the passed location object.
* We use the {@link Shaper} class to generate the cube, which allows us to define
* custom shapes using {@link DoubleUnaryOperator}s.
*
* @param location The location to center the cube around.
* @param material The material to use for the cube.
* @return The center location of the cube (the passed location).
* @see Shaper
* @see DoubleUnaryOperator
*/
public Location createCage(final Location location, final Material material)
{
final Shaper shaper = new Shaper(location.getWorld(), 0.0, 4.0);
final List<Location> cubed = new LinkedList<>();
cubed.addAll(shaper.generate(5, t -> t, t -> 4.0, t -> t));
cubed.addAll(shaper.generate(5, t -> t, t -> 0.0, t -> t));
cubed.addAll(shaper.generate(5, t -> 0.0, t -> t, t -> t));
cubed.addAll(shaper.generate(5, t -> 4.0, t -> t, t -> t));
cubed.addAll(shaper.generate(5, t -> t, t -> t, t -> 0.0));
cubed.addAll(shaper.generate(5, t -> t, t -> t, t -> 4.0));
for (final Location l : cubed)
{
location.getWorld().getBlockAt(l).setType(material);
}
return location.clone(); // Return the passed location as that is the center of the cube.
}
private final class CageListener implements Listener
{
@EventHandler
public void blockBreakEvent(final BlockBreakEvent event)
{
if (cagedPlayers.contains(event.getPlayer().getUniqueId()))
if (cagedPlayers.contains(event.getPlayer()
.getUniqueId()))
{
event.setCancelled(true);
}
@ -164,9 +170,11 @@ public class Cager extends Service
@EventHandler
public void playerLeaveEvent(final PlayerQuitEvent event)
{
if (cagedPlayers.contains(event.getPlayer().getUniqueId()))
if (cagedPlayers.contains(event.getPlayer()
.getUniqueId()))
{
uncagePlayer(event.getPlayer().getUniqueId());
uncagePlayer(event.getPlayer()
.getUniqueId());
}
}
}

View File

@ -25,7 +25,8 @@ public class Halter implements Listener
@EventHandler
public void playerMove(final PlayerMoveEvent event)
{
if (haltedPlayers.contains(event.getPlayer().getUniqueId()))
if (haltedPlayers.contains(event.getPlayer()
.getUniqueId()))
{
event.setCancelled(true);
}

View File

@ -22,15 +22,23 @@ public class Locker extends Service
super("locker-service");
}
public void lock(final UUID uuid)
public void lock(final Player player)
{
lockedPlayers.add(uuid);
lockedPlayers.add(player.getUniqueId());
}
public void unlock(final Player player)
{
lockedPlayers.remove(player.getUniqueId());
}
@Override
public void tick()
{
lockedPlayers.removeIf(uuid -> !CommonsBase.getInstance().getServer().getOfflinePlayer(uuid).isOnline());
lockedPlayers.removeIf(uuid -> !CommonsBase.getInstance()
.getServer()
.getOfflinePlayer(uuid)
.isOnline());
for (final UUID uuid : lockedPlayers)
{
@ -43,8 +51,10 @@ public class Locker extends Service
private void lockingMethod(@NotNull final Player player)
{
final double x = player.getLocation().getX();
final double z = player.getLocation().getZ();
final double x = player.getLocation()
.getX();
final double z = player.getLocation()
.getZ();
if ((x / z % 0.001) < 1)
{
@ -65,13 +75,15 @@ public class Locker extends Service
player.openInventory(Bukkit.createInventory(null, 54));
player.closeInventory(InventoryCloseEvent.Reason.UNKNOWN);
player.teleport(player.getLocation().clone());
player.teleport(player.getLocation()
.clone());
final SplittableRandom random = new SplittableRandom();
player.getEyeLocation().add(new Vector(
random.nextDouble(-1.0, 1.0),
random.nextDouble(-1.0, 1.0),
random.nextDouble(-1.0, 1.0)
));
player.getEyeLocation()
.add(new Vector(
random.nextDouble(-1.0, 1.0),
random.nextDouble(-1.0, 1.0),
random.nextDouble(-1.0, 1.0)
));
}
}

View File

@ -1,89 +0,0 @@
package me.totalfreedom.datura.sql;
import me.totalfreedom.base.CommonsBase;
import me.totalfreedom.datura.banning.SimpleBan;
import me.totalfreedom.security.ban.Ban;
import me.totalfreedom.security.ban.BanID;
import me.totalfreedom.sql.SQL;
import me.totalfreedom.utils.FreedomLogger;
import java.sql.SQLException;
import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class DBBan
{
private final SQL sql;
public DBBan(final SQL sql)
{
this.sql = sql;
}
public CompletableFuture<Ban> fromSQL(final BanID id)
{
return sql.executeQuery("SELECT * FROM bans WHERE id = ?", id.getID())
.thenApplyAsync(result ->
{
try
{
if (result.next())
{
final UUID uuid = UUID.fromString(result.getString("uuid"));
final Instant timestamp = Instant.parse(result.getString("timestamp"));
final Instant expiry;
final String ex = result.getString("expiry");
if (ex.equals("-1"))
{
expiry = null;
} else
{
expiry = Instant.parse(ex);
}
return new SimpleBan(uuid,
result.getString("reason"),
result.getString("issuer"),
timestamp,
expiry);
}
} catch (SQLException e)
{
FreedomLogger.getLogger("Datura")
.error(e.getMessage());
}
return null;
}, CommonsBase.getInstance().getExecutor().getAsync());
}
public void addBan(final Ban ban)
{
sql.executeUpdate("INSERT INTO bans (id, uuid, reason, issuer, timestamp, expiry) VALUES (?, ?, ?, ?, ?, ?)",
ban.getBanID().getID(),
ban.getOffenderID().toString(),
ban.getReason(),
ban.getBanIssuer(),
ban.getCreationTime().toString(),
(ban.getExpiry() != null ? ban.getExpiry().toString() : "-1")
);
}
public boolean hasEntry(final UUID uuid) {
return sql.executeQuery("SELECT * FROM bans WHERE uuid = ?", uuid.toString())
.thenApplyAsync(result ->
{
try
{
return result.next();
} catch (SQLException e)
{
FreedomLogger.getLogger("Datura")
.error(e.getMessage());
}
return false;
}, CommonsBase.getInstance().getExecutor().getAsync())
.join();
}
}

View File

@ -2,6 +2,7 @@ package me.totalfreedom.datura.sql;
import me.totalfreedom.base.CommonsBase;
import me.totalfreedom.sql.SQL;
import me.totalfreedom.utils.Identity;
import java.sql.Connection;
import java.sql.DriverManager;
@ -13,10 +14,18 @@ import java.util.concurrent.CompletionException;
public class MySQL implements SQL
{
private String url = "jdbc:mysql://";
/**
* Using StringBuilder for finality.
*/
private final StringBuilder url = new StringBuilder("jdbc:mysql://");
public MySQL(final String host, final int port, final String database) {
url += host + ":" + port + "/" + database;
public MySQL(final String host, final int port, final String database)
{
url.append(host)
.append(':')
.append(port)
.append('/')
.append(database);
}
/**
@ -26,85 +35,130 @@ public class MySQL implements SQL
* @param username The username to add
* @param password The password to add
*/
public void addCredentials(final String username, final String password) {
if (url.contains("?user=")) {
url = url.split("\\x3f")[0];
public void addCredentials(final String username, final String password)
{
if (url.toString()
.contains("?user="))
{
final String split = url.toString()
.split("\\x3f")[0];
url.setLength(0);
url.append(split);
}
url += "?user=" + username + "&password=" + password;
url.append("?user=")
.append(username)
.append("&password=")
.append(password);
}
@Override
public CompletableFuture<Connection> getConnection(final String url)
public CompletableFuture<ResultSet> getRow(final String table, final String column, final Identity identity)
{
return CompletableFuture.supplyAsync(() -> {
try {
return DriverManager.getConnection(url);
} catch (SQLException ex) {
throw new CompletionException("Failed to connect to the database: "
+ url + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
return executeQuery("SELECT * FROM ? WHERE ? = ?", table, column, identity.getId());
}
@Override
public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args)
{
return getConnection(url)
.thenApplyAsync(connection -> {
try {
final PreparedStatement statement = connection.prepareStatement(query);
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
return statement;
} catch (SQLException ex) {
throw new CompletionException("Failed to prepare statement: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
return getConnection()
.thenApplyAsync(connection ->
{
try
{
final PreparedStatement statement = connection.prepareStatement(query);
for (int i = 0; i < args.length; i++)
{
statement.setObject(i + 1, args[i]);
}
return statement;
}
catch (SQLException ex)
{
throw new CompletionException("Failed to prepare statement: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
private CompletableFuture<Connection> getConnection()
{
return CompletableFuture.supplyAsync(() ->
{
try
{
return DriverManager.getConnection(url.toString());
}
catch (SQLException ex)
{
throw new CompletionException("Failed to connect to the database: "
+ url.toString() + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<ResultSet> executeQuery(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.executeQuery();
} catch (SQLException ex) {
throw new CompletionException("Failed to retrieve a result set from query: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
.thenApplyAsync(statement ->
{
try
{
return statement.executeQuery();
}
catch (SQLException ex)
{
throw new CompletionException(
"Failed to retrieve a result set from query: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<Integer> executeUpdate(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.executeUpdate();
} catch (SQLException ex) {
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
.thenApplyAsync(statement ->
{
try
{
return statement.executeUpdate();
}
catch (SQLException ex)
{
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<Boolean> execute(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement -> {
try {
return statement.execute();
} catch (SQLException ex) {
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
.thenApplyAsync(statement ->
{
try
{
return statement.execute();
}
catch (SQLException ex)
{
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
@Override
@ -113,9 +167,11 @@ public class MySQL implements SQL
final StringBuilder query = new StringBuilder();
query.append("CREATE TABLE IF NOT EXISTS ? (");
for (int i = 0; i < columns.length; i++) {
for (int i = 0; i < columns.length; i++)
{
query.append("?");
if (i != columns.length - 1) {
if (i != columns.length - 1)
{
query.append(", ");
}
}
@ -123,4 +179,90 @@ public class MySQL implements SQL
return execute(query.toString(), table, columns);
}
public <T> CompletableFuture<T> getColumn(final String table, final String column, final String key,
final Identity identity, final Class<T> type)
{
return executeQuery("SELECT ? FROM ? WHERE ? = ?", column, table, key, identity.getId())
.thenApplyAsync(resultSet ->
{
try
{
if (resultSet.next())
{
return resultSet.getObject(column, type);
}
}
catch (SQLException ex)
{
throw new CompletionException(
"Failed to retrieve column: " + column + " from table: " + table + " " +
"where primary key: " + key + " is equal to: " + identity.getId() + "\n",
ex);
}
return null;
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> updateColumn(final String table, final String column, final Object value,
final String key, final Identity identity)
{
return executeUpdate("UPDATE ? SET ? = ? WHERE ? = ?", table, column, value, key, identity.getId())
.thenApplyAsync(result -> result > 0, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> deleteRow(final String table, final String key, final Identity identity)
{
return executeUpdate("DELETE FROM ? WHERE ? = ?", table, key, identity.getId())
.thenApplyAsync(result -> result > 0, CommonsBase.getInstance()
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> insertRow(final String table, final Object... values)
{
final StringBuilder query = new StringBuilder();
query.append("INSERT INTO ? VALUES (");
for (int i = 0; i < values.length; i++)
{
query.append("?");
if (i != values.length - 1)
{
query.append(", ");
}
}
query.append(")");
return execute(query.toString(), table, values);
}
public CompletableFuture<Boolean> insertRow(final String table, final String[] columns, final Object... values)
{
final StringBuilder query = new StringBuilder();
query.append("INSERT INTO ? (");
for (int i = 0; i < columns.length; i++)
{
query.append("?");
if (i != columns.length - 1)
{
query.append(", ");
}
}
query.append(") VALUES (");
for (int i = 0; i < values.length; i++)
{
query.append("?");
if (i != values.length - 1)
{
query.append(", ");
}
}
query.append(")");
return execute(query.toString(), table, columns, values);
}
}

View File

@ -0,0 +1,14 @@
package me.totalfreedom.datura.sql;
import com.google.errorprone.annotations.Immutable;
/**
* Represents a single result from a result set.
*/
@Immutable
public record Result(String name, Object value)
{
}

View File

@ -38,20 +38,22 @@ public class SimpleUserData implements UserData
this.username = player.getName();
this.user = new FreedomUser(player);
CommonsBase.getInstance().getEventBus().addEvent(event);
CommonsBase.getInstance()
.getEventBus()
.addEvent(event);
}
private SimpleUserData(
final UUID uuid,
final String username,
final User user,
final Group group,
final long playtime,
final boolean frozen,
final boolean canInteract,
final boolean caged,
final long balance,
final boolean transactionsFrozen)
final UUID uuid,
final String username,
final User user,
final Group group,
final long playtime,
final boolean frozen,
final boolean canInteract,
final boolean caged,
final long balance,
final boolean transactionsFrozen)
{
this.uuid = uuid;
this.username = username;
@ -68,57 +70,64 @@ public class SimpleUserData implements UserData
public static SimpleUserData fromSQL(final SQL sql, final String uuid)
{
return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid)
.thenApplyAsync(result ->
{
try
{
if (result.next())
{
final String g = result.getString("group");
.thenApplyAsync(result ->
{
try
{
if (result.next())
{
final String g = result.getString("group");
final UUID u = UUID.fromString(uuid);
final String username = result.getString("username");
final UUID u = UUID.fromString(uuid);
final String username = result.getString("username");
final Player player = Bukkit.getPlayer(u);
final Player player = Bukkit.getPlayer(u);
if (player == null)
throw new IllegalStateException("Player should be online but they are not!");
if (player == null)
throw new IllegalStateException(
"Player should be online but they are not!");
final User user = new FreedomUser(player);
final Group group = CommonsBase.getInstance()
.getRegistrations()
.getGroupRegistry()
.getGroup(g);
final User user = new FreedomUser(player);
final Group group = CommonsBase.getInstance()
.getRegistrations()
.getGroupRegistry()
.getGroup(g);
final long playtime = result.getLong("playtime");
final boolean frozen = result.getBoolean("frozen");
final boolean canInteract = result.getBoolean("canInteract");
final boolean caged = result.getBoolean("caged");
final long balance = result.getLong("balance");
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen");
return new SimpleUserData(u, username, user, group, playtime, frozen, canInteract, caged, balance, transactionsFrozen);
}
} catch (SQLException ex)
{
final String sb = "An error occurred while trying to retrieve user data for UUID " +
uuid +
" from the database." +
"\nCaused by: " +
ExceptionUtils.getRootCauseMessage(ex) +
"\nStack trace: " +
ExceptionUtils.getStackTrace(ex);
final long playtime = result.getLong("playtime");
final boolean frozen = result.getBoolean("frozen");
final boolean canInteract = result.getBoolean("canInteract");
final boolean caged = result.getBoolean("caged");
final long balance = result.getLong("balance");
final boolean transactionsFrozen = result.getBoolean(
"transactionsFrozen");
return new SimpleUserData(u, username, user, group, playtime, frozen,
canInteract, caged, balance,
transactionsFrozen);
}
}
catch (SQLException ex)
{
final String sb = "An error occurred while trying to retrieve user data for" +
" UUID " +
uuid +
" from the database." +
"\nCaused by: " +
ExceptionUtils.getRootCauseMessage(ex) +
"\nStack trace: " +
ExceptionUtils.getStackTrace(ex);
FreedomLogger.getLogger("Datura")
.error(sb);
}
FreedomLogger.getLogger("Datura")
.error(sb);
}
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
if (player == null) throw new IllegalStateException("Player should be online but they are not!");
return new SimpleUserData(player);
}, CommonsBase.getInstance()
.getExecutor()
.getAsync())
.join();
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
if (player == null) throw new IllegalStateException(
"Player should be online but they are not!");
return new SimpleUserData(player);
}, CommonsBase.getInstance()
.getExecutor()
.getAsync())
.join();
}
@Override
@ -230,6 +239,12 @@ public class SimpleUserData implements UserData
return balance.get();
}
@Override
public void setBalance(final long newBalance)
{
balance.set(newBalance);
}
@Override
public long addToBalance(final long amount)
{
@ -241,10 +256,4 @@ public class SimpleUserData implements UserData
{
return balance.addAndGet(-amount);
}
@Override
public void setBalance(final long newBalance)
{
balance.set(newBalance);
}
}