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

@ -22,13 +22,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
java-version: '17' java-version: '17'
distribution: 'temurin' distribution: 'temurin'
- name: Build with Gradle - name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with: with:
arguments: build arguments: build

View File

@ -6,18 +6,20 @@ import org.bukkit.plugin.java.JavaPlugin;
public class Corvo extends JavaPlugin public class Corvo extends JavaPlugin
{ {
@Override @Override
public void onEnable() { public void onDisable()
{
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getModuleRegistry() .getModuleRegistry()
.addModule(this); .removeModule(this);
} }
@Override @Override
public void onDisable() { public void onEnable()
{
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getModuleRegistry() .getModuleRegistry()
.removeModule(this); .addModule(this);
} }
} }

View File

@ -20,18 +20,40 @@ public class Datura extends JavaPlugin
public void onEnable() public void onEnable()
{ {
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getModuleRegistry() .getModuleRegistry()
.addModule(this); .addModule(this);
CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, locker); CommonsBase.getInstance()
CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, cager); .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() public MySQL getSQL()
{ {
return sql; 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 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(); 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; private final PermissionAttachment attachment;
public FreedomGroup(final Component name, public FreedomGroup(final Component name,
final Component prefix, final Component prefix,
final Component abbreviation, final Component abbreviation,
final int weight, final int weight,
final boolean isDefault, final boolean isDefault,
final boolean isHidden) final boolean isHidden)
{ {
this.name = name; this.name = name;
this.prefix = prefix; this.prefix = prefix;
@ -44,6 +44,12 @@ public class FreedomGroup implements Group
this.attachment = new PermissionAttachment(CommonsBase.getInstance(), this); this.attachment = new PermissionAttachment(CommonsBase.getInstance(), this);
} }
@Override
public UUID getUniqueId()
{
return UUID.nameUUIDFromBytes(getName().toString()
.getBytes());
}
@Override @Override
public Component getName() public Component getName()
@ -81,12 +87,6 @@ public class FreedomGroup implements Group
return isHidden; return isHidden;
} }
@Override
public UUID getUniqueId()
{
return UUID.nameUUIDFromBytes(getName().toString().getBytes());
}
@Override @Override
public Set<Node> permissions() public Set<Node> permissions()
{ {
@ -109,9 +109,10 @@ public class FreedomGroup implements Group
public boolean isPermissionSet(@NotNull final String name) public boolean isPermissionSet(@NotNull final String name)
{ {
final Node node = permissions().stream() final Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name)) .filter(n -> n.key()
.findFirst() .equalsIgnoreCase(name))
.orElse(null); .findFirst()
.orElse(null);
return node != null && node.value(); return node != null && node.value();
} }
@ -120,10 +121,11 @@ public class FreedomGroup implements Group
public boolean isPermissionSet(@NotNull final Permission perm) public boolean isPermissionSet(@NotNull final Permission perm)
{ {
final Node node = permissions() final Node node = permissions()
.stream() .stream()
.filter(n -> n.bukkit().equals(perm)) .filter(n -> n.bukkit()
.findFirst() .equals(perm))
.orElse(null); .findFirst()
.orElse(null);
return node != null && node.value(); return node != null && node.value();
} }
@ -132,9 +134,10 @@ public class FreedomGroup implements Group
public boolean hasPermission(@NotNull final String name) public boolean hasPermission(@NotNull final String name)
{ {
final Node node = permissions().stream() final Node node = permissions().stream()
.filter(n -> n.key().equalsIgnoreCase(name)) .filter(n -> n.key()
.findFirst() .equalsIgnoreCase(name))
.orElse(null); .findFirst()
.orElse(null);
return node != null && node.value(); return node != null && node.value();
} }
@ -143,10 +146,11 @@ public class FreedomGroup implements Group
public boolean hasPermission(@NotNull final Permission perm) public boolean hasPermission(@NotNull final Permission perm)
{ {
final Node node = permissions() final Node node = permissions()
.stream() .stream()
.filter(n -> n.bukkit().equals(perm)) .filter(n -> n.bukkit()
.findFirst() .equals(perm))
.orElse(null); .findFirst()
.orElse(null);
return node != null && node.value(); return node != null && node.value();
} }
@ -164,7 +168,8 @@ public class FreedomGroup implements Group
* @return This group's PermissionAttachment. * @return This group's PermissionAttachment.
*/ */
@Override @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); attachment.setPermission(name, value);
return attachment; return attachment;
@ -177,7 +182,8 @@ public class FreedomGroup implements Group
} }
@Override @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); attachment.setPermission(name, value);
return attachment; return attachment;
@ -205,23 +211,23 @@ public class FreedomGroup implements Group
public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions() public @NotNull Set<PermissionAttachmentInfo> getEffectivePermissions()
{ {
return permissions() return permissions()
.stream() .stream()
.map(n -> new PermissionAttachmentInfo( .map(n -> new PermissionAttachmentInfo(
this, this,
n.key(), n.key(),
attachment, attachment,
n.value())) n.value()))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@Override @Override
public boolean isOp() public boolean isOp()
{ {
final Node node = permissions() final Node node = permissions()
.stream() .stream()
.filter(n -> n.equals(DefaultNodes.OP)) .filter(n -> n.equals(DefaultNodes.OP))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
return node != null && node.value(); return node != null && node.value();
} }

View File

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

View File

@ -9,29 +9,31 @@ record PermissionNode(String key,
boolean value, boolean value,
long expiry, long expiry,
NodeType type, NodeType type,
boolean wildcard, boolean wildcard) implements Node
boolean negated) implements Node
{ {
@Override @Override
public Permission bukkit() public Permission bukkit()
{ {
return new Permission(key(), return new Permission(key(),
value() ? PermissionDefault.TRUE : PermissionDefault.FALSE); value()
? PermissionDefault.TRUE
: PermissionDefault.FALSE);
} }
@Override @Override
public boolean compare(final Node node) public boolean compare(final Node node)
{ {
return node.key().equalsIgnoreCase(key()) return node.key()
&& node.value() == value() .equalsIgnoreCase(key())
&& node.type() == type(); && node.value() == value()
&& node.type() == type();
} }
@Override @Override
public boolean isExpired() public boolean isExpired()
{ {
if (isPermanent()) if (!isTemporary())
{ {
return false; return false;
} }
@ -39,15 +41,9 @@ record PermissionNode(String key,
return System.currentTimeMillis() > expiry(); return System.currentTimeMillis() > expiry();
} }
@Override
public boolean isPermanent()
{
return expiry() == -1;
}
@Override @Override
public boolean isTemporary() 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.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -31,7 +31,8 @@ public class Cager extends Service
super("cage_service"); super("cage_service");
this.cagedPlayers = new HashSet<>(); this.cagedPlayers = new HashSet<>();
this.cageLocations = new HashMap<>(); 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)); 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) public void cagePlayer(final UUID uuid, final Material material)
{ {
final Player player = Bukkit.getPlayer(uuid); final Player player = Bukkit.getPlayer(uuid);
@ -92,12 +126,14 @@ public class Cager extends Service
final Location cageLocation = getCageLocation(player); final Location cageLocation = getCageLocation(player);
final boolean inside; final boolean inside;
if (!player.getWorld().equals(cageLocation.getWorld())) if (!player.getWorld()
.equals(cageLocation.getWorld()))
{ {
inside = false; inside = false;
} else } 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) if (!inside)
@ -119,43 +155,13 @@ public class Cager extends Service
return cageLocations.get(player.getUniqueId()); 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 private final class CageListener implements Listener
{ {
@EventHandler @EventHandler
public void blockBreakEvent(final BlockBreakEvent event) public void blockBreakEvent(final BlockBreakEvent event)
{ {
if (cagedPlayers.contains(event.getPlayer().getUniqueId())) if (cagedPlayers.contains(event.getPlayer()
.getUniqueId()))
{ {
event.setCancelled(true); event.setCancelled(true);
} }
@ -164,9 +170,11 @@ public class Cager extends Service
@EventHandler @EventHandler
public void playerLeaveEvent(final PlayerQuitEvent event) 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 @EventHandler
public void playerMove(final PlayerMoveEvent event) public void playerMove(final PlayerMoveEvent event)
{ {
if (haltedPlayers.contains(event.getPlayer().getUniqueId())) if (haltedPlayers.contains(event.getPlayer()
.getUniqueId()))
{ {
event.setCancelled(true); event.setCancelled(true);
} }

View File

@ -22,15 +22,23 @@ public class Locker extends Service
super("locker-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 @Override
public void tick() 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) for (final UUID uuid : lockedPlayers)
{ {
@ -43,8 +51,10 @@ public class Locker extends Service
private void lockingMethod(@NotNull final Player player) private void lockingMethod(@NotNull final Player player)
{ {
final double x = player.getLocation().getX(); final double x = player.getLocation()
final double z = player.getLocation().getZ(); .getX();
final double z = player.getLocation()
.getZ();
if ((x / z % 0.001) < 1) if ((x / z % 0.001) < 1)
{ {
@ -65,13 +75,15 @@ public class Locker extends Service
player.openInventory(Bukkit.createInventory(null, 54)); player.openInventory(Bukkit.createInventory(null, 54));
player.closeInventory(InventoryCloseEvent.Reason.UNKNOWN); player.closeInventory(InventoryCloseEvent.Reason.UNKNOWN);
player.teleport(player.getLocation().clone()); player.teleport(player.getLocation()
.clone());
final SplittableRandom random = new SplittableRandom(); final SplittableRandom random = new SplittableRandom();
player.getEyeLocation().add(new Vector( player.getEyeLocation()
random.nextDouble(-1.0, 1.0), .add(new Vector(
random.nextDouble(-1.0, 1.0), random.nextDouble(-1.0, 1.0),
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.base.CommonsBase;
import me.totalfreedom.sql.SQL; import me.totalfreedom.sql.SQL;
import me.totalfreedom.utils.Identity;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
@ -13,10 +14,18 @@ import java.util.concurrent.CompletionException;
public class MySQL implements SQL 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) { public MySQL(final String host, final int port, final String database)
url += host + ":" + port + "/" + 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 username The username to add
* @param password The password to add * @param password The password to add
*/ */
public void addCredentials(final String username, final String password) { public void addCredentials(final String username, final String password)
if (url.contains("?user=")) { {
url = url.split("\\x3f")[0]; 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<ResultSet> getRow(final String table, final String column, final Identity identity)
public CompletableFuture<Connection> getConnection(final String url)
{ {
return CompletableFuture.supplyAsync(() -> { return executeQuery("SELECT * FROM ? WHERE ? = ?", table, column, identity.getId());
try {
return DriverManager.getConnection(url);
} catch (SQLException ex) {
throw new CompletionException("Failed to connect to the database: "
+ url + "\n", ex);
}
}, CommonsBase.getInstance().getExecutor().getAsync());
} }
@Override @Override
public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args) public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args)
{ {
return getConnection(url) return getConnection()
.thenApplyAsync(connection -> { .thenApplyAsync(connection ->
try { {
final PreparedStatement statement = connection.prepareStatement(query); try
for (int i = 0; i < args.length; i++) { {
statement.setObject(i + 1, args[i]); final PreparedStatement statement = connection.prepareStatement(query);
} for (int i = 0; i < args.length; i++)
return statement; {
} catch (SQLException ex) { statement.setObject(i + 1, args[i]);
throw new CompletionException("Failed to prepare statement: " }
+ query + "\n", ex); return statement;
} }
}, CommonsBase.getInstance().getExecutor().getAsync()); 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 @Override
public CompletableFuture<ResultSet> executeQuery(final String query, final Object... args) public CompletableFuture<ResultSet> executeQuery(final String query, final Object... args)
{ {
return prepareStatement(query, args) return prepareStatement(query, args)
.thenApplyAsync(statement -> { .thenApplyAsync(statement ->
try { {
return statement.executeQuery(); try
} catch (SQLException ex) { {
throw new CompletionException("Failed to retrieve a result set from query: " return statement.executeQuery();
+ query + "\n", ex); }
} catch (SQLException ex)
}, CommonsBase.getInstance().getExecutor().getAsync()); {
throw new CompletionException(
"Failed to retrieve a result set from query: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
} }
@Override @Override
public CompletableFuture<Integer> executeUpdate(final String query, final Object... args) public CompletableFuture<Integer> executeUpdate(final String query, final Object... args)
{ {
return prepareStatement(query, args) return prepareStatement(query, args)
.thenApplyAsync(statement -> { .thenApplyAsync(statement ->
try { {
return statement.executeUpdate(); try
} catch (SQLException ex) { {
throw new CompletionException("Failed to execute update: " return statement.executeUpdate();
+ query + "\n", ex); }
} catch (SQLException ex)
}, CommonsBase.getInstance().getExecutor().getAsync()); {
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
} }
@Override @Override
public CompletableFuture<Boolean> execute(final String query, final Object... args) public CompletableFuture<Boolean> execute(final String query, final Object... args)
{ {
return prepareStatement(query, args) return prepareStatement(query, args)
.thenApplyAsync(statement -> { .thenApplyAsync(statement ->
try { {
return statement.execute(); try
} catch (SQLException ex) { {
throw new CompletionException("Failed to execute statement: " return statement.execute();
+ query + "\n", ex); }
} catch (SQLException ex)
}, CommonsBase.getInstance().getExecutor().getAsync()); {
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
}, CommonsBase.getInstance()
.getExecutor()
.getAsync());
} }
@Override @Override
@ -113,9 +167,11 @@ public class MySQL implements SQL
final StringBuilder query = new StringBuilder(); final StringBuilder query = new StringBuilder();
query.append("CREATE TABLE IF NOT EXISTS ? ("); 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("?"); query.append("?");
if (i != columns.length - 1) { if (i != columns.length - 1)
{
query.append(", "); query.append(", ");
} }
} }
@ -123,4 +179,90 @@ public class MySQL implements SQL
return execute(query.toString(), table, columns); 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.username = player.getName();
this.user = new FreedomUser(player); this.user = new FreedomUser(player);
CommonsBase.getInstance().getEventBus().addEvent(event); CommonsBase.getInstance()
.getEventBus()
.addEvent(event);
} }
private SimpleUserData( private SimpleUserData(
final UUID uuid, final UUID uuid,
final String username, final String username,
final User user, final User user,
final Group group, final Group group,
final long playtime, final long playtime,
final boolean frozen, final boolean frozen,
final boolean canInteract, final boolean canInteract,
final boolean caged, final boolean caged,
final long balance, final long balance,
final boolean transactionsFrozen) final boolean transactionsFrozen)
{ {
this.uuid = uuid; this.uuid = uuid;
this.username = username; this.username = username;
@ -68,57 +70,64 @@ public class SimpleUserData implements UserData
public static SimpleUserData fromSQL(final SQL sql, final String uuid) public static SimpleUserData fromSQL(final SQL sql, final String uuid)
{ {
return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid) return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid)
.thenApplyAsync(result -> .thenApplyAsync(result ->
{ {
try try
{ {
if (result.next()) if (result.next())
{ {
final String g = result.getString("group"); final String g = result.getString("group");
final UUID u = UUID.fromString(uuid); final UUID u = UUID.fromString(uuid);
final String username = result.getString("username"); final String username = result.getString("username");
final Player player = Bukkit.getPlayer(u); final Player player = Bukkit.getPlayer(u);
if (player == null) if (player == null)
throw new IllegalStateException("Player should be online but they are not!"); throw new IllegalStateException(
"Player should be online but they are not!");
final User user = new FreedomUser(player); final User user = new FreedomUser(player);
final Group group = CommonsBase.getInstance() final Group group = CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getGroupRegistry() .getGroupRegistry()
.getGroup(g); .getGroup(g);
final long playtime = result.getLong("playtime"); final long playtime = result.getLong("playtime");
final boolean frozen = result.getBoolean("frozen"); final boolean frozen = result.getBoolean("frozen");
final boolean canInteract = result.getBoolean("canInteract"); final boolean canInteract = result.getBoolean("canInteract");
final boolean caged = result.getBoolean("caged"); final boolean caged = result.getBoolean("caged");
final long balance = result.getLong("balance"); final long balance = result.getLong("balance");
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen"); final boolean transactionsFrozen = result.getBoolean(
return new SimpleUserData(u, username, user, group, playtime, frozen, canInteract, caged, balance, transactionsFrozen); "transactionsFrozen");
} return new SimpleUserData(u, username, user, group, playtime, frozen,
} catch (SQLException ex) canInteract, caged, balance,
{ transactionsFrozen);
final String sb = "An error occurred while trying to retrieve user data for UUID " + }
uuid + }
" from the database." + catch (SQLException ex)
"\nCaused by: " + {
ExceptionUtils.getRootCauseMessage(ex) + final String sb = "An error occurred while trying to retrieve user data for" +
"\nStack trace: " + " UUID " +
ExceptionUtils.getStackTrace(ex); uuid +
" from the database." +
"\nCaused by: " +
ExceptionUtils.getRootCauseMessage(ex) +
"\nStack trace: " +
ExceptionUtils.getStackTrace(ex);
FreedomLogger.getLogger("Datura") FreedomLogger.getLogger("Datura")
.error(sb); .error(sb);
} }
final Player player = Bukkit.getPlayer(UUID.fromString(uuid)); final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
if (player == null) throw new IllegalStateException("Player should be online but they are not!"); if (player == null) throw new IllegalStateException(
return new SimpleUserData(player); "Player should be online but they are not!");
}, CommonsBase.getInstance() return new SimpleUserData(player);
.getExecutor() }, CommonsBase.getInstance()
.getAsync()) .getExecutor()
.join(); .getAsync())
.join();
} }
@Override @Override
@ -230,6 +239,12 @@ public class SimpleUserData implements UserData
return balance.get(); return balance.get();
} }
@Override
public void setBalance(final long newBalance)
{
balance.set(newBalance);
}
@Override @Override
public long addToBalance(final long amount) public long addToBalance(final long amount)
{ {
@ -241,10 +256,4 @@ public class SimpleUserData implements UserData
{ {
return balance.addAndGet(-amount); return balance.addAndGet(-amount);
} }
@Override
public void setBalance(final long newBalance)
{
balance.set(newBalance);
}
} }

View File

@ -9,8 +9,8 @@ public class Fossil extends JavaPlugin
public void onEnable() public void onEnable()
{ {
CommonsBase.getInstance() CommonsBase.getInstance()
.getRegistrations() .getRegistrations()
.getModuleRegistry() .getModuleRegistry()
.addModule(this); .addModule(this);
} }
} }

View File

@ -7,9 +7,9 @@ import java.util.concurrent.atomic.AtomicLong;
public class SimpleTransaction implements Transaction public class SimpleTransaction implements Transaction
{ {
protected final AtomicLong balance;
private final EconomicEntity source; private final EconomicEntity source;
private final EconomicEntity destination; private final EconomicEntity destination;
protected final AtomicLong balance;
public SimpleTransaction(final EconomicEntity source, final EconomicEntity destination, final long balance) public SimpleTransaction(final EconomicEntity source, final EconomicEntity destination, final long balance)
{ {

View File

@ -1,10 +1,10 @@
package me.totalfreedom.fossil.economy; package me.totalfreedom.fossil.economy;
import me.totalfreedom.audience.MutableAudienceForwarder; import me.totalfreedom.audience.MutableAudienceForwarder;
import me.totalfreedom.economy.TransactionResult;
import me.totalfreedom.economy.CompletedTransaction; import me.totalfreedom.economy.CompletedTransaction;
import me.totalfreedom.economy.TransactionLogger;
import me.totalfreedom.economy.EconomicEntity; import me.totalfreedom.economy.EconomicEntity;
import me.totalfreedom.economy.TransactionLogger;
import me.totalfreedom.economy.TransactionResult;
import me.totalfreedom.utils.FreedomLogger; import me.totalfreedom.utils.FreedomLogger;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@ -24,17 +24,19 @@ public class SimpleTransactionLogger implements TransactionLogger
final EconomicEntity destination = completedTransaction.getDestination(); final EconomicEntity destination = completedTransaction.getDestination();
final long transactionAmount = completedTransaction.getBalance(); final long transactionAmount = completedTransaction.getBalance();
transactionLoggingStatementBuilder.append(resultSuccess ? "Successful" : "Unsuccessful") transactionLoggingStatementBuilder.append(resultSuccess
.append(" (") ? "Successful"
.append(resultMessage) : "Unsuccessful")
.append(") ") .append(" (")
.append(" transaction between ") .append(resultMessage)
.append(source.getName()) .append(") ")
.append(" ") .append(" transaction between ")
.append(destination.getName()) .append(source.getName())
.append(" where the volume of currency transferred was $") .append(" ")
.append(transactionAmount) .append(destination.getName())
.append("."); .append(" where the volume of currency transferred was $")
.append(transactionAmount)
.append(".");
final Component message = Component.text(transactionLoggingStatementBuilder.toString()); final Component message = Component.text(transactionLoggingStatementBuilder.toString());

View File

@ -7,16 +7,21 @@ import net.kyori.adventure.text.format.NamedTextColor;
public class SimpleTransactionResult implements TransactionResult public class SimpleTransactionResult implements TransactionResult
{ {
public static final TransactionResult SUCCESSFUL = new SimpleTransactionResult("Successful transaction.", true); public static final TransactionResult SUCCESSFUL = new SimpleTransactionResult("Successful transaction.", true);
public static final TransactionResult UNAUTHORIZED = new SimpleTransactionResult("Unauthorized transaction.", false); public static final TransactionResult UNAUTHORIZED = new SimpleTransactionResult("Unauthorized transaction.",
public static final TransactionResult AMOUNT_TOO_SMALL = new SimpleTransactionResult("Transaction balance too small.", false); false);
public static final TransactionResult INSUFFICIENT_FUNDS = new SimpleTransactionResult("The source has an insufficient balance to carry out this transaction.", false); public static final TransactionResult AMOUNT_TOO_SMALL = new SimpleTransactionResult(
"Transaction balance too small.", false);
public static final TransactionResult INSUFFICIENT_FUNDS = new SimpleTransactionResult(
"The source has an insufficient balance to carry out this transaction.", false);
private final String message; private final String message;
private final Component component; private final Component component;
private final boolean successful; private final boolean successful;
public SimpleTransactionResult(final String message, final boolean successful) public SimpleTransactionResult(final String message, final boolean successful)
{ {
this(message, Component.text(message, successful ? NamedTextColor.GREEN : NamedTextColor.RED), successful); this(message, Component.text(message, successful
? NamedTextColor.GREEN
: NamedTextColor.RED), successful);
} }
public SimpleTransactionResult(final String message, final Component component, final boolean successful) public SimpleTransactionResult(final String message, final Component component, final boolean successful)

View File

@ -0,0 +1,5 @@
package me.totalfreedom.fossil.shop;
public class Shoppe
{
}

View File

@ -0,0 +1,11 @@
package me.totalfreedom.fossil.shop.menus;
import me.totalfreedom.display.AbstractMenu;
public final class MainMenu extends AbstractMenu
{
protected MainMenu(final int size)
{
super(size);
}
}

View File

@ -16,13 +16,13 @@ import java.util.function.Function;
@FunctionalInterface @FunctionalInterface
public interface Context<T> public interface Context<T>
{ {
T get();
default <S> Context<S> map(@NotNull final Function<T, S> mapper) default <S> Context<S> map(@NotNull final Function<T, S> mapper)
{ {
return () -> mapper.apply(get()); return () -> mapper.apply(get());
} }
T get();
default @Nullable String asString() default @Nullable String asString()
{ {
if (get() instanceof String string) if (get() instanceof String string)
@ -56,26 +56,35 @@ public interface Context<T>
} }
} }
default @Nullable Integer asInt() { default @Nullable Integer asInt()
if (get() instanceof Integer integer) { {
if (get() instanceof Integer integer)
{
return integer; return integer;
} else { } else
{
return null; return null;
} }
} }
default @Nullable Long asLong() { default @Nullable Long asLong()
if (get() instanceof Long longg) { {
if (get() instanceof Long longg)
{
return longg; return longg;
} else { } else
{
return null; return null;
} }
} }
default @Nullable Float asFloat() { default @Nullable Float asFloat()
if (get() instanceof Float floatt) { {
if (get() instanceof Float floatt)
{
return floatt; return floatt;
} else { } else
{
return null; return null;
} }
} }

View File

@ -19,7 +19,8 @@ import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
* A replacement for {@link net.kyori.adventure.audience.ForwardingAudience} that allows for audiences to be removed & added at will. Not thread safe. * A replacement for {@link net.kyori.adventure.audience.ForwardingAudience} that allows for audiences to be removed
* & added at will. Not thread safe.
* <p> * <p>
* This is intended for use in toggleable logging systems, for example, potion spy. * This is intended for use in toggleable logging systems, for example, potion spy.
*/ */
@ -60,9 +61,9 @@ public class MutableAudienceForwarder implements Audience
public @NotNull Audience filterAudience(@NotNull final Predicate<? super Audience> filter) public @NotNull Audience filterAudience(@NotNull final Predicate<? super Audience> filter)
{ {
return audiences.stream() return audiences.stream()
.filter(filter) .filter(filter)
.findFirst() .findFirst()
.orElseThrow(); .orElseThrow();
} }
@Override @Override

View File

@ -16,25 +16,23 @@ public class CommonsBase extends JavaPlugin
} }
@Override @Override
public void onEnable() public void onDisable()
{ {
getRegistrations().getServiceRegistry().register(this, eventBus); getRegistrations().getServiceRegistry()
getExecutor().getSync() .stopAll();
.execute(() -> getRegistrations() getRegistrations().getServiceRegistry()
.getServiceRegistry() .unregister(EventBus.class, eventBus);
.startAll());
} }
@Override @Override
public void onDisable() public void onEnable()
{ {
getRegistrations().getServiceRegistry().stopAll(); getRegistrations().getServiceRegistry()
getRegistrations().getServiceRegistry().unregister(EventBus.class, eventBus); .register(this, eventBus);
} getExecutor().getSync()
.execute(() -> getRegistrations()
public Registration getRegistrations() .getServiceRegistry()
{ .startAll());
return registration;
} }
public FreedomExecutor getExecutor() public FreedomExecutor getExecutor()
@ -42,6 +40,11 @@ public class CommonsBase extends JavaPlugin
return executor; return executor;
} }
public Registration getRegistrations()
{
return registration;
}
public EventBus getEventBus() public EventBus getEventBus()
{ {
return eventBus; return eventBus;

View File

@ -1,12 +1,11 @@
package me.totalfreedom.base; package me.totalfreedom.base;
import me.totalfreedom.data.GroupRegistry;
import me.totalfreedom.data.BanRegistry;
import me.totalfreedom.data.ConfigRegistry; import me.totalfreedom.data.ConfigRegistry;
import me.totalfreedom.data.EventRegistry;
import me.totalfreedom.data.GroupRegistry;
import me.totalfreedom.data.ModuleRegistry; import me.totalfreedom.data.ModuleRegistry;
import me.totalfreedom.data.ServiceRegistry; import me.totalfreedom.data.ServiceRegistry;
import me.totalfreedom.data.UserRegistry; import me.totalfreedom.data.UserRegistry;
import me.totalfreedom.data.EventRegistry;
public class Registration public class Registration
{ {
@ -15,7 +14,6 @@ public class Registration
private final ServiceRegistry serviceRegistry; private final ServiceRegistry serviceRegistry;
private final ModuleRegistry moduleRegistry; private final ModuleRegistry moduleRegistry;
private final GroupRegistry groupRegistry; private final GroupRegistry groupRegistry;
private final BanRegistry banRegistry;
private final ConfigRegistry configRegistry; private final ConfigRegistry configRegistry;
public Registration() public Registration()
@ -25,8 +23,7 @@ public class Registration
this.serviceRegistry = new ServiceRegistry(); this.serviceRegistry = new ServiceRegistry();
this.moduleRegistry = new ModuleRegistry(); this.moduleRegistry = new ModuleRegistry();
this.groupRegistry = new GroupRegistry(); this.groupRegistry = new GroupRegistry();
this.banRegistry = new BanRegistry(); this.configRegistry = new ConfigRegistry();
this.configRegistry = new ConfigRegistry();
} }
public ModuleRegistry getModuleRegistry() public ModuleRegistry getModuleRegistry()
@ -54,11 +51,6 @@ public class Registration
return groupRegistry; return groupRegistry;
} }
public BanRegistry getBanRegistry()
{
return banRegistry;
}
public ConfigRegistry getConfigRegistry() public ConfigRegistry getConfigRegistry()
{ {
return configRegistry; return configRegistry;

View File

@ -0,0 +1,188 @@
package me.totalfreedom.command;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.provider.ContextProvider;
import me.totalfreedom.utils.FreedomLogger;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class BukkitDelegate extends Command implements PluginIdentifiableCommand
{
private final JavaPlugin plugin;
private final Commander command;
private final boolean noConsole;
BukkitDelegate(final Commander command)
{
super(command.getInfo()
.name());
this.command = command;
this.plugin = command.getPlugin();
this.setDescription(command.getInfo()
.description());
this.setUsage(command.getInfo()
.usage());
this.setPermission(command.getPerms()
.perm());
this.setAliases(Arrays.asList(command.getInfo()
.aliases()));
this.permissionMessage(Component.text(command.getPerms()
.noPerms()));
this.noConsole = command.getPerms()
.onlyPlayers();
}
@Override
public boolean execute(@NotNull final CommandSender sender,
@NotNull final String commandLabel,
@NotNull final String[] args)
{
if (sender instanceof ConsoleCommandSender && noConsole)
{
sender.sendMessage(Component.text("This command can only be run by players."));
return true;
}
if (getPermission() != null && !sender.hasPermission(getPermission()))
{
Component permissionMessage = permissionMessage();
if (permissionMessage == null)
permissionMessage = Component.text("You do not have permission to use this command.");
sender.sendMessage(permissionMessage);
return true;
}
if (args.length > 0)
{
final ContextProvider provider = new ContextProvider();
final Set<Subcommand> nodes = command.getSubcommands()
.keySet();
for (final Subcommand node : nodes)
{
processSubCommands(args, sender, provider, node);
}
return true;
}
if (command.getBaseMethod() != null)
{
try
{
command.getBaseMethod()
.invoke(command, sender);
}
catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
return true;
}
return false;
}
private void processSubCommands(final @NotNull String @NotNull [] args,
final CommandSender sender, final ContextProvider provider,
final Subcommand node)
{
final Class<?>[] argTypes = node.args();
if (argTypes.length != args.length)
return;
final Object[] objects = new Object[argTypes.length + 1];
for (int i = 0; i < argTypes.length; i++)
{
final Class<?> argType = argTypes[i];
final String arg = args[i];
if (argType == String.class)
continue;
final Context<?> context = () -> provider.fromString(arg, argType);
objects[i] = context.get();
}
try
{
command.getSubcommands()
.get(node)
.invoke(command, sender, objects);
}
catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
}
@Override
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args)
{
final Set<Completion> completions = command.getCompletions();
final List<String> results = new ArrayList<>();
for (final Completion completion : completions)
{
if (completion.index() != args.length)
{
continue;
}
for (final String p : completion.args())
{
switch (p)
{
case "%player%" -> results.addAll(Bukkit.getOnlinePlayers()
.stream()
.map(Player::getName)
.toList());
case "%world%" -> results.addAll(Bukkit.getWorlds()
.stream()
.map(World::getName)
.toList());
case "%number%" -> results.addAll(List.of(
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"));
case "%location%" -> results.add("world,x,y,z");
default -> results.add(p);
}
}
}
return results.stream()
.filter(s -> s.startsWith(args[args.length - 1]))
.toList();
}
@Override
public @NotNull Plugin getPlugin()
{
return this.plugin;
}
}

View File

@ -1,171 +0,0 @@
package me.totalfreedom.command;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.annotation.Completion;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.provider.ContextProvider;
import me.totalfreedom.utils.FreedomLogger;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class BukkitDelegator extends Command implements PluginIdentifiableCommand
{
private final JavaPlugin plugin;
private final CommandBase command;
private final boolean noConsole;
BukkitDelegator(final JavaPlugin plugin, final CommandBase command)
{
super(command.getInfo().name());
this.command = command;
this.plugin = command.getPlugin();
this.setDescription(command.getInfo().description());
this.setUsage(command.getInfo().usage());
this.setPermission(command.getPerms().perm());
this.setAliases(Arrays.asList(command.getInfo().aliases()));
this.permissionMessage(Component.text(command.getPerms().noPerms()));
this.noConsole = command.getPerms().onlyPlayers();
}
@Override
public boolean execute(@NotNull final CommandSender sender,
@NotNull final String commandLabel,
@NotNull final String[] args)
{
if (commandLabel.isEmpty() || !commandLabel.equalsIgnoreCase(getName()))
return false;
if (sender instanceof ConsoleCommandSender && noConsole)
{
sender.sendMessage(Component.text("This command can only be run by players."));
return true;
}
if (getPermission() != null && !sender.hasPermission(getPermission()))
{
Component permissionMessage = permissionMessage();
if (permissionMessage == null)
permissionMessage = Component.text("You do not have permission to use this command.");
sender.sendMessage(permissionMessage);
return true;
}
if (args.length > 0)
{
final ContextProvider provider = new ContextProvider();
final Set<Subcommand> nodes = command.getSubcommands().keySet();
for (final Subcommand node : nodes)
{
final Class<?>[] argTypes = node.args();
if (argTypes.length != args.length)
continue;
Object[] objects = new Object[0];
for (int i = 0; i < argTypes.length; i++)
{
final Class<?> argType = argTypes[i];
final String arg = args[i];
if (argType == String.class)
continue;
final Context<?> context = () -> provider.fromString(arg);
if (!argType.isInstance(context.get()))
{
throw new IllegalStateException(); // TODO: Change this.
}
objects = Arrays.copyOf(objects, objects.length + 1);
objects[objects.length - 1] = context.get();
}
try
{
command.getSubcommands().get(node).invoke(command, objects);
} catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
}
return false;
}
if (command.getBaseMethodPair() != null)
{
try
{
command.getBaseMethodPair().value().invoke(command, sender);
} catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
}
return true;
}
@Override
public List<String> tabComplete(final CommandSender sender, final String alias, final String[] args)
{
final Set<Completion> completions = command.getCompletions();
final List<String> results = new ArrayList<>();
for (final Completion completion : completions)
{
if (completion.index() != args.length)
{
continue;
}
for (final String p : completion.args())
{
switch (p)
{
case "%player%" -> results.addAll(Bukkit.getOnlinePlayers()
.stream()
.map(Player::getName)
.toList());
case "%world%" -> results.addAll(Bukkit.getWorlds()
.stream()
.map(World::getName)
.toList());
case "%number%" -> results.addAll(List.of(
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"));
case "%location%" -> results.add("world,x,y,z");
default -> results.add(p);
}
}
}
return results.stream().filter(s -> s.startsWith(args[args.length - 1])).toList();
}
@Override
public @NotNull Plugin getPlugin()
{
return this.plugin;
}
}

View File

@ -1,89 +0,0 @@
package me.totalfreedom.command;
import me.totalfreedom.command.annotation.*;
import me.totalfreedom.utils.Pair;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Stream;
public abstract class CommandBase
{
private final JavaPlugin plugin;
private final Info info;
private final Permissive perms;
private final Map<Subcommand, Method> subcommands;
private final Set<Completion> completions;
private final Pair<Base, Method> baseMethodPair;
protected CommandBase(final JavaPlugin plugin)
{
this.info = this.getClass().getDeclaredAnnotation(Info.class);
this.perms = this.getClass().getDeclaredAnnotation(Permissive.class);
this.plugin = plugin;
this.subcommands = new HashMap<>();
this.completions = new HashSet<>();
if (this.getClass().isAnnotationPresent(Base.class))
{
final Method method = Stream.of(this.getClass().getDeclaredMethods())
.filter(m -> m.isAnnotationPresent(Base.class))
.findFirst()
.orElseThrow(() -> new RuntimeException("Base annotation present but no method found."));
this.baseMethodPair = new Pair<>(method.getDeclaredAnnotation(Base.class), method);
} else
{
this.baseMethodPair = null;
}
registerAnnotations();
}
private void registerAnnotations()
{
Stream.of(this.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(Subcommand.class))
.forEach(method -> this.subcommands.put(
method.getDeclaredAnnotation(Subcommand.class),
method));
List.of(this.getClass().getDeclaredAnnotationsByType(Completion.class))
.stream()
.forEach(completions::add);
}
public Pair<Base, Method> getBaseMethodPair()
{
return baseMethodPair;
}
Info getInfo()
{
return this.info;
}
Permissive getPerms()
{
return this.perms;
}
public JavaPlugin getPlugin()
{
return this.plugin;
}
Map<Subcommand, Method> getSubcommands()
{
return this.subcommands;
}
Set<Completion> getCompletions()
{
return this.completions;
}
}

View File

@ -12,14 +12,11 @@ public class CommandHandler
this.plugin = plugin; this.plugin = plugin;
} }
// TODO: Figure out how to use CommandExecutor and TabCompleter. public <T extends Commander> void registerCommand(final T command)
// We need to find a way to resolve PluginCommands so we can
// set the executor and tab completer as necessary.
// OR we need to find an alternative way to process tab completions.
public <T extends CommandBase> void registerCommand(final T command)
{ {
final BukkitDelegator delegate = new BukkitDelegator(plugin, command); final BukkitDelegate delegate = new BukkitDelegate(command);
Bukkit.getCommandMap().register(plugin.getName(), delegate); Bukkit.getCommandMap()
.register(plugin.getName(), delegate);
} }
} }

View File

@ -0,0 +1,108 @@
package me.totalfreedom.command;
import me.totalfreedom.command.annotation.Base;
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 org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
public abstract class Commander
{
private final JavaPlugin plugin;
private final Info info;
private final Permissive perms;
private final Map<Subcommand, Method> subcommands;
private final Set<Completion> completions;
private final Method baseMethod;
protected Commander(final @NotNull JavaPlugin plugin)
{
this.info = this.getClass()
.getDeclaredAnnotation(Info.class);
this.perms = this.getClass()
.getDeclaredAnnotation(Permissive.class);
this.plugin = plugin;
this.subcommands = new HashMap<>();
this.completions = new HashSet<>();
if (this.getClass()
.isAnnotationPresent(Base.class))
{
final Method method = Stream.of(this.getClass()
.getDeclaredMethods())
.filter(m -> m.isAnnotationPresent(Base.class))
.findFirst()
.orElseThrow(() -> new RuntimeException(
"Base annotation present but no method found."));
this.baseMethod = method;
} else
{
this.baseMethod = null;
}
registerAnnotations();
}
private void registerAnnotations()
{
Stream.of(this.getClass()
.getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(Subcommand.class))
.forEach(method -> this.subcommands.put(
method.getDeclaredAnnotation(Subcommand.class),
method));
List.of(this.getClass()
.getDeclaredAnnotationsByType(Completion.class))
.stream()
.forEach(completions::add);
}
@Nullable
public Method getBaseMethod()
{
return baseMethod;
}
@NotNull
Info getInfo()
{
return this.info;
}
@NotNull
Permissive getPerms()
{
return this.perms;
}
@NotNull
public JavaPlugin getPlugin()
{
return this.plugin;
}
@NotNull
Map<Subcommand, Method> getSubcommands()
{
return this.subcommands;
}
@Nullable
Set<Completion> getCompletions()
{
return this.completions;
}
}

View File

@ -1,11 +1,13 @@
package me.totalfreedom.command.annotation; package me.totalfreedom.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.METHOD)
@Repeatable(Completions.class)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Completion public @interface Completion
{ {

View File

@ -0,0 +1,13 @@
package me.totalfreedom.command.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Completions
{
Completion[] value();
}

View File

@ -1,8 +1,11 @@
package me.totalfreedom.command.annotation; package me.totalfreedom.command.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Subcommand public @interface Subcommand
{ {

View File

@ -1,34 +0,0 @@
package me.totalfreedom.data;
import me.totalfreedom.security.ban.Ban;
import me.totalfreedom.security.ban.BanID;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BanRegistry
{
private final List<Ban> bansList = new ArrayList<>();
public boolean addBan(final Ban ban) {
return bansList.add(ban);
}
public boolean removeBan(final Ban ban) {
return bansList.remove(ban);
}
@Nullable
public Ban getBan(final BanID banID)
{
for (final Ban ban : bansList)
{
if (ban.getBanID().matches(banID))
{
return ban;
}
}
return null;
}
}

View File

@ -15,26 +15,32 @@ public class GroupRegistry
this.groups = new ArrayList<>(); this.groups = new ArrayList<>();
} }
public boolean registerGroup(final Group group) { public boolean registerGroup(final Group group)
{
return groups.add(group); return groups.add(group);
} }
public boolean unregisterGroup(final Group group) { public boolean unregisterGroup(final Group group)
{
return groups.remove(group); return groups.remove(group);
} }
public Group getGroup(final String name) { public Group getGroup(final String name)
{
final PlainTextComponentSerializer s = PlainTextComponentSerializer.plainText(); final PlainTextComponentSerializer s = PlainTextComponentSerializer.plainText();
for (final Group group : groups) { for (final Group group : groups)
{
final String n = s.serialize(group.getName()); final String n = s.serialize(group.getName());
if (n.equalsIgnoreCase(name)) { if (n.equalsIgnoreCase(name))
{
return group; return group;
} }
} }
return null; return null;
} }
public List<Group> getGroups() { public List<Group> getGroups()
{
return groups; return groups;
} }
} }

View File

@ -24,7 +24,8 @@ public class ModuleRegistry
this.plugins.add(plugin); this.plugins.add(plugin);
} }
public void removeModule(final JavaPlugin plugin) { public void removeModule(final JavaPlugin plugin)
{
this.plugins.remove(plugin); this.plugins.remove(plugin);
} }

View File

@ -42,29 +42,34 @@ public class ServiceRegistry
public <T extends Service> void register(final Plugin plugin, final T service) public <T extends Service> void register(final Plugin plugin, final T service)
{ {
this.services.add(service); this.services.add(service);
if (!service.getClass().isInstance(service)) if (!service.getClass()
.isInstance(service))
{ {
throw new UnknownError(""" throw new UnknownError("""
A critical issue has been encountered: A critical issue has been encountered:
The service %s is not an instance of itself. The service %s is not an instance of itself.
This is a critical issue and should be reported immediately. This is a critical issue and should be reported immediately.
""".formatted(service.getClass().getName())); """.formatted(service.getClass()
.getName()));
} }
Bukkit.getServicesManager().register( Bukkit.getServicesManager()
(Class<T>) service.getClass(), .register(
service, (Class<T>) service.getClass(),
plugin, service,
ServicePriority.Normal); plugin,
ServicePriority.Normal);
} }
public <T extends Service> RegisteredServiceProvider<T> getService(final Class<T> clazz) public <T extends Service> RegisteredServiceProvider<T> getService(final Class<T> clazz)
{ {
return Bukkit.getServicesManager().getRegistration(clazz); return Bukkit.getServicesManager()
.getRegistration(clazz);
} }
public void unregister(final Class<? extends Service> clazz, final Service service) public void unregister(final Class<? extends Service> clazz, final Service service)
{ {
this.services.remove(service); this.services.remove(service);
Bukkit.getServicesManager().unregister(clazz, service); Bukkit.getServicesManager()
.unregister(clazz, service);
} }
} }

View File

@ -0,0 +1,121 @@
package me.totalfreedom.display;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public abstract class AbstractMenu
{
private static final Map<UUID, AbstractMenu> invByUUID = new HashMap<>();
private static final Map<UUID, UUID> openInvs = new HashMap<>();
private final Map<Integer, ClickAction> actionMap;
private final Displayable displayable;
private final UUID displayableUUID;
protected AbstractMenu(final int size)
{
actionMap = new HashMap<>();
this.displayable = new Displayable(size);
this.displayableUUID = UUID.randomUUID();
invByUUID.put(getDisplayableUUID(), this);
}
public UUID getDisplayableUUID()
{
return displayableUUID;
}
public static Map<UUID, AbstractMenu> getInvByUUID()
{
return invByUUID;
}
public static Map<UUID, UUID> getOpenInvs()
{
return openInvs;
}
public void setItem(final int slot, final @NotNull ItemStack stack)
{
setItem(slot, stack, null);
}
public void setItem(final int slot, final @NotNull ItemStack stack, final @Nullable ClickAction action)
{
getDisplayable().setItem(slot, stack);
if (action != null)
{
actionMap.put(slot, action);
}
}
public Displayable getDisplayable()
{
return displayable;
}
public void open(final @NotNull Player player)
{
player.openInventory(getDisplayable());
openInvs.put(player.getUniqueId(), getDisplayableUUID());
}
public void delete()
{
Bukkit.getOnlinePlayers()
.forEach(player ->
{
if (openInvs.get(player.getUniqueId())
.equals(getDisplayableUUID()))
{
close(player);
}
});
invByUUID.remove(getDisplayableUUID());
}
public void close(final @NotNull Player player)
{
player.closeInventory();
openInvs.remove(player.getUniqueId());
}
public Map<Integer, ClickAction> getActions()
{
return actionMap;
}
public ItemStack newItem(final @NotNull Material material, final @NotNull Component name)
{
return this.newItem(material, name, new Component[0]);
}
public ItemStack newItem(final @NotNull Material material, final @NotNull Component name,
final @NotNull Component... lore)
{
final ItemStack item = new ItemStack(material, 1);
final ItemMeta meta = item.getItemMeta();
if (meta == null)
{
return item;
}
meta.displayName(name);
final List<Component> metaLore = Arrays.asList(lore);
meta.lore(metaLore);
item.setItemMeta(meta);
return item;
}
}

View File

@ -0,0 +1,9 @@
package me.totalfreedom.display;
import org.bukkit.entity.Player;
@FunctionalInterface
public interface ClickAction
{
void onClick(final Player player);
}

View File

@ -1,5 +1,6 @@
package me.totalfreedom.display; package me.totalfreedom.display;
import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
@ -14,11 +15,11 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
public abstract class Displayable implements Inventory, InventoryHolder public final class Displayable implements Inventory, InventoryHolder
{ {
private final int size; private final int size;
private final ItemStack[] contents; private ItemStack[] contents;
protected Displayable(final int size) protected Displayable(final int size)
{ {
@ -27,9 +28,9 @@ public abstract class Displayable implements Inventory, InventoryHolder
throw new IllegalArgumentException("Invalid size for Displayable inventory"); throw new IllegalArgumentException("Invalid size for Displayable inventory");
} }
this.size = (size % 9 == 0) // If the size is not a multiple of nine, find the difference to the next highest multiple of 9 and make up
? size // the difference.
: size + (9 - size % 9); this.size = (size % 9 == 0) ? size : size + (9 - size % 9);
this.contents = new ItemStack[size]; this.contents = new ItemStack[size];
} }
@ -78,7 +79,8 @@ public abstract class Displayable implements Inventory, InventoryHolder
} }
@Override @Override
public @NotNull HashMap<Integer, ItemStack> addItem(final @NotNull ItemStack... items) throws IllegalArgumentException public @NotNull HashMap<Integer, ItemStack> addItem(final @NotNull ItemStack... items)
throws IllegalArgumentException
{ {
final HashMap<Integer, ItemStack> remainingItems = new HashMap<>(); final HashMap<Integer, ItemStack> remainingItems = new HashMap<>();
@ -116,7 +118,8 @@ public abstract class Displayable implements Inventory, InventoryHolder
} }
@Override @Override
public @NotNull HashMap<Integer, ItemStack> removeItem(final @NotNull ItemStack... items) throws IllegalArgumentException public @NotNull HashMap<Integer, ItemStack> removeItem(final @NotNull ItemStack... items)
throws IllegalArgumentException
{ {
final HashMap<Integer, ItemStack> removedItems = new HashMap<>(); final HashMap<Integer, ItemStack> removedItems = new HashMap<>();
@ -148,13 +151,21 @@ public abstract class Displayable implements Inventory, InventoryHolder
if (remainingAmount < item.getAmount()) if (remainingAmount < item.getAmount())
{ {
removedItems.put(removedItems.size(), new ItemStack(item.getType(), item.getAmount() - remainingAmount)); removedItems.put(removedItems.size(),
new ItemStack(item.getType(), item.getAmount() - remainingAmount));
} }
} }
return removedItems; return removedItems;
} }
@Override
public @NotNull HashMap<Integer, ItemStack> removeItemAnySlot(final @NotNull ItemStack... items)
throws IllegalArgumentException
{
return removeItem(items);
}
@Override @Override
public @Nullable ItemStack @NotNull [] getContents() public @Nullable ItemStack @NotNull [] getContents()
{ {
@ -176,39 +187,15 @@ public abstract class Displayable implements Inventory, InventoryHolder
} }
@Override @Override
public @NotNull ListIterator<ItemStack> iterator() public @Nullable ItemStack @NotNull [] getStorageContents()
{ {
return iterator(0); return contents;
} }
@Override @Override
public @NotNull ListIterator<ItemStack> iterator(final int index) public void setStorageContents(final @Nullable ItemStack @NotNull [] items) throws IllegalArgumentException
{ {
return List.of(contents).listIterator(index); this.contents = items;
}
@Override
public @NotNull InventoryType getType()
{
return InventoryType.CHEST;
}
@Override
public @Nullable InventoryHolder getHolder()
{
return this;
}
@Override
public @Nullable InventoryHolder getHolder(final boolean useSnapshot)
{
return this;
}
@Override
public @NotNull List<HumanEntity> getViewers()
{
return new ArrayList<>();
} }
@Override @Override
@ -272,7 +259,7 @@ public abstract class Displayable implements Inventory, InventoryHolder
if (content != null && content.isSimilar(item)) if (content != null && content.isSimilar(item))
{ {
totalAmount += content.getAmount(); totalAmount += content.getAmount();
if (totalAmount >= amount) if (totalAmount == amount)
{ {
return true; return true;
} }
@ -304,7 +291,8 @@ public abstract class Displayable implements Inventory, InventoryHolder
} }
@Override @Override
public @NotNull HashMap<Integer, ? extends ItemStack> all(final @NotNull Material material) throws IllegalArgumentException public @NotNull HashMap<Integer, ? extends ItemStack> all(final @NotNull Material material)
throws IllegalArgumentException
{ {
final HashMap<Integer, ItemStack> matchingItems = new HashMap<>(); final HashMap<Integer, ItemStack> matchingItems = new HashMap<>();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
@ -439,4 +427,53 @@ public abstract class Displayable implements Inventory, InventoryHolder
{ {
return 0; return 0;
} }
@Override
public @NotNull List<HumanEntity> getViewers()
{
return new ArrayList<>();
}
@Override
public @NotNull InventoryType getType()
{
return InventoryType.CHEST;
}
@Override
public @Nullable InventoryHolder getHolder()
{
return this;
}
@Override
public @Nullable InventoryHolder getHolder(final boolean useSnapshot)
{
return this;
}
@Override
public @NotNull ListIterator<ItemStack> iterator()
{
return iterator(0);
}
@Override
public @NotNull ListIterator<ItemStack> iterator(final int index)
{
return List.of(contents)
.listIterator(index);
}
@Override
public @Nullable Location getLocation()
{
return null;
}
@Override
public @NotNull Inventory getInventory()
{
return this;
}
} }

View File

@ -16,7 +16,8 @@ public class DisplayableView extends InventoryView
private final InventoryType type; private final InventoryType type;
private String title; private String title;
public DisplayableView(final Player player, final Displayable top, final Displayable bottom) { public DisplayableView(final Player player, final Displayable top, final Displayable bottom)
{
this.player = player; this.player = player;
this.top = top; this.top = top;
this.bottom = bottom; this.bottom = bottom;

View File

@ -6,9 +6,9 @@ public interface EconomicEntityData
long getBalance(); long getBalance();
void setBalance(final long newBalance);
long addToBalance(final long amount); long addToBalance(final long amount);
long removeFromBalance(final long amount); long removeFromBalance(final long amount);
void setBalance(final long newBalance);
} }

View File

@ -1,7 +1,8 @@
package me.totalfreedom.economy; package me.totalfreedom.economy;
/** /**
* Please ensure that all modifications of {@link MutableTransaction} happen BEFORE it is passed to a {@link Transactor} implementation * Please ensure that all modifications of {@link MutableTransaction} happen BEFORE it is passed to a
* {@link Transactor} implementation
*/ */
public interface MutableTransaction extends Transaction public interface MutableTransaction extends Transaction
{ {

View File

@ -27,9 +27,10 @@ public class EventBus extends Service
public <T extends FEvent> T getEvent(final Class<T> eventClass) public <T extends FEvent> T getEvent(final Class<T> eventClass)
{ {
final FEvent e = eventSet.stream() final FEvent e = eventSet.stream()
.filter(event -> event.getEventClass().equals(eventClass)) .filter(event -> event.getEventClass()
.findFirst() .equals(eventClass))
.orElse(null); .findFirst()
.orElse(null);
return eventClass.cast(e); return eventClass.cast(e);
} }
@ -37,10 +38,11 @@ public class EventBus extends Service
public <T extends FEvent> EventSubscription<T> subscribe(final Class<T> eventClass, final Callback<T> callback) public <T extends FEvent> EventSubscription<T> subscribe(final Class<T> eventClass, final Callback<T> callback)
{ {
final Context<T> eventContext = () -> eventSet.stream() final Context<T> eventContext = () -> eventSet.stream()
.filter(event -> event.getEventClass().equals(eventClass)) .filter(event -> event.getEventClass()
.findFirst() .equals(eventClass))
.map(eventClass::cast) .findFirst()
.orElse(null); .map(eventClass::cast)
.orElse(null);
if (eventContext.get() == null) if (eventContext.get() == null)
{ {

View File

@ -7,24 +7,32 @@ class SubscriptionBox<T extends FEvent>
{ {
private final List<EventSubscription<T>> subscriptions; private final List<EventSubscription<T>> subscriptions;
public SubscriptionBox() { public SubscriptionBox()
{
this.subscriptions = new ArrayList<>(); this.subscriptions = new ArrayList<>();
} }
public void addSubscription(final EventSubscription<T> subscription) { public void addSubscription(final EventSubscription<T> subscription)
{
subscriptions.add(subscription); subscriptions.add(subscription);
} }
public void removeSubscription(final EventSubscription<?> subscription) { public void removeSubscription(final EventSubscription<?> subscription)
{
subscriptions.remove(subscription); subscriptions.remove(subscription);
} }
public void tick() { public void tick()
subscriptions.forEach(s -> { {
if (!s.event().shouldCall()) return; subscriptions.forEach(s ->
{
if (!s.event()
.shouldCall()) return;
s.callback().call(s.event()); s.callback()
s.event().reset(); .call(s.event());
}); s.event()
.reset();
});
} }
} }

View File

@ -1,11 +1,31 @@
package me.totalfreedom.particle; package me.totalfreedom.particle;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public interface Trail public interface Trail
{ {
@NotNull
UUID getAssocPlayerUUID();
// Nullable because the player may not be online and trail selections should be persistent whether they are
// active or not.
@Nullable
Player getAssocPlayer();
@NotNull
TrailType getTrailType(); TrailType getTrailType();
@Nullable Color getColor(); @NotNull
Color getColor();
void setColor(@NotNull Color color);
boolean isActive();
void setActive(boolean active);
} }

View File

@ -14,21 +14,22 @@ import java.util.stream.Stream;
public class ContextProvider public class ContextProvider
{ {
public Object fromString(final String string) public <T> T fromString(final String string, final Class<T> clazz)
{ {
return Stream.of(toBoolean(string), return Stream.of(toBoolean(string),
toDouble(string), toDouble(string),
toInt(string), toInt(string),
toLong(string), toLong(string),
toFloat(string), toFloat(string),
toPlayer(string), toPlayer(string),
toWorld(string), toWorld(string),
toLocation(string), toLocation(string),
toCommandSender(string), toCommandSender(string),
toComponent(string)) toComponent(string))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.findFirst() .findFirst()
.orElse(string); .map(clazz::cast)
.orElse(null);
} }
private @Nullable Boolean toBoolean(final String string) private @Nullable Boolean toBoolean(final String string)
@ -36,7 +37,8 @@ public class ContextProvider
try try
{ {
return Boolean.parseBoolean(string); return Boolean.parseBoolean(string);
} catch (Exception e) }
catch (Exception ignored)
{ {
return null; return null;
} }
@ -47,7 +49,8 @@ public class ContextProvider
try try
{ {
return Double.parseDouble(string); return Double.parseDouble(string);
} catch (Exception e) }
catch (Exception ignored)
{ {
return null; return null;
} }
@ -58,7 +61,8 @@ public class ContextProvider
try try
{ {
return Integer.parseInt(string); return Integer.parseInt(string);
} catch (Exception e) }
catch (Exception ignored)
{ {
return null; return null;
} }
@ -69,7 +73,8 @@ public class ContextProvider
try try
{ {
return Long.parseLong(string); return Long.parseLong(string);
} catch (Exception e) }
catch (Exception ignored)
{ {
return null; return null;
} }
@ -80,7 +85,8 @@ public class ContextProvider
try try
{ {
return Float.parseFloat(string); return Float.parseFloat(string);
} catch (Exception e) }
catch (Exception ignored)
{ {
return null; return null;
} }
@ -91,20 +97,11 @@ public class ContextProvider
return Bukkit.getPlayer(string); return Bukkit.getPlayer(string);
} }
private @Nullable CommandSender toCommandSender(final String string)
{
if (toPlayer(string) == null) return null;
return toPlayer(string);
}
private @Nullable World toWorld(final String string) private @Nullable World toWorld(final String string)
{ {
return Bukkit.getWorld(string); return Bukkit.getWorld(string);
} }
// If we decide to, we can "modify" this to use spaces
// and adjust our inputs accordingly.
/** /**
* When using this method, the input string must be formatted as * When using this method, the input string must be formatted as
* <br> * <br>
@ -127,6 +124,13 @@ public class ContextProvider
return new Location(toWorld(split[0]), x, y, z); return new Location(toWorld(split[0]), x, y, z);
} }
private @Nullable CommandSender toCommandSender(final String string)
{
if (toPlayer(string) == null) return null;
return toPlayer(string);
}
private @NotNull Component toComponent(final String string) private @NotNull Component toComponent(final String string)
{ {
return Component.text(string); return Component.text(string);

View File

@ -3,10 +3,10 @@ package me.totalfreedom.security.ban;
/** /**
* Represents an ID for a ban. These are formatted either as: * Represents an ID for a ban. These are formatted either as:
* <p> * <p>
* P-00129381 * P-00129381
* <br> * <br>
* T-00128381 * T-00128381
* <br> * <br>
* </p> * </p>
* Where P marks a ban as permanent, and T marks a ban as temporary. * Where P marks a ban as permanent, and T marks a ban as temporary.
*/ */
@ -19,6 +19,23 @@ public interface BanID
*/ */
String getID(); String getID();
/**
* Checks the prefix of the Ban ID to see whether if it is permanent.
*
* @return true if the Ban ID is prefixed with a P, false otherwise.
*/
boolean isPermanent();
default boolean matches(BanID other)
{
if (other == null)
{
return false;
}
return (getIDPrefix() == other.getIDPrefix())
&& (getNumericalTag() == other.getNumericalTag());
}
/** /**
* This method returns the ban type denominator character for the Ban ID. * This method returns the ban type denominator character for the Ban ID.
* This would either be T or P, where T = temporary and P = permanent. * This would either be T or P, where T = temporary and P = permanent.
@ -34,19 +51,4 @@ public interface BanID
* @return The numerical tag of this ban ID. * @return The numerical tag of this ban ID.
*/ */
int getNumericalTag(); int getNumericalTag();
/**
* Checks the prefix of the Ban ID to see whether if it is permanent.
*
* @return true if the Ban ID is prefixed with a P, false otherwise.
*/
boolean isPermanent();
default boolean matches(BanID other) {
if (other == null) {
return false;
}
return (getIDPrefix() == other.getIDPrefix())
&& (getNumericalTag() == other.getNumericalTag());
}
} }

View File

@ -21,11 +21,7 @@ public interface Node
boolean isExpired(); boolean isExpired();
boolean isPermanent();
boolean isTemporary(); boolean isTemporary();
boolean wildcard(); boolean wildcard();
boolean negated();
} }

View File

@ -13,38 +13,30 @@ public class FreedomExecutor
public FreedomExecutor() public FreedomExecutor()
{ {
syncExecutor = r -> Bukkit.getScheduler().runTask(CommonsBase.getInstance(), r); syncExecutor = r -> Bukkit.getScheduler()
asyncExecutor = r -> Bukkit.getScheduler().runTaskAsynchronously(CommonsBase.getInstance(), r); .runTask(CommonsBase.getInstance(), r);
} asyncExecutor = r -> Bukkit.getScheduler()
.runTaskAsynchronously(CommonsBase.getInstance(), r);
public Executor getSync()
{
return syncExecutor;
}
public Executor getAsync()
{
return asyncExecutor;
} }
public Executor scheduled(final long delay, final long period) public Executor scheduled(final long delay, final long period)
{ {
return r -> Bukkit.getScheduler() return r -> Bukkit.getScheduler()
.runTaskTimer( .runTaskTimer(
CommonsBase.getInstance(), CommonsBase.getInstance(),
r, r,
delay, delay,
period); period);
} }
public Executor scheduledAsync(final long delay, final long period) public Executor scheduledAsync(final long delay, final long period)
{ {
return r -> Bukkit.getScheduler() return r -> Bukkit.getScheduler()
.runTaskTimerAsynchronously( .runTaskTimerAsynchronously(
CommonsBase.getInstance(), CommonsBase.getInstance(),
r, r,
delay, delay,
period); period);
} }
public void runSync(@NotNull final Task task) public void runSync(@NotNull final Task task)
@ -52,8 +44,18 @@ public class FreedomExecutor
getSync().execute(task); getSync().execute(task);
} }
public Executor getSync()
{
return syncExecutor;
}
public void runAsync(@NotNull final Task task) public void runAsync(@NotNull final Task task)
{ {
getAsync().execute(task); getAsync().execute(task);
} }
public Executor getAsync()
{
return asyncExecutor;
}
} }

View File

@ -17,24 +17,24 @@ public abstract class Service
{ {
isActive = true; isActive = true;
CommonsBase.getInstance() CommonsBase.getInstance()
.getExecutor() .getExecutor()
.getSync() .getSync()
.execute(() -> .execute(() ->
{ {
while (isActive) while (isActive)
{ {
tick(); tick();
} }
}); });
} }
public abstract void tick();
public void stop() public void stop()
{ {
isActive = false; isActive = false;
} }
public abstract void tick();
public String getName() public String getName()
{ {
return name; return name;

View File

@ -1,14 +1,11 @@
package me.totalfreedom.sql; package me.totalfreedom.sql;
import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface SQL public interface SQL
{ {
CompletableFuture<Connection> getConnection(final String url);
CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args); CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args);
CompletableFuture<ResultSet> executeQuery(final String query, final Object... args); CompletableFuture<ResultSet> executeQuery(final String query, final Object... args);

View File

@ -19,6 +19,15 @@ public interface SQLProperties
return properties; return properties;
} }
default String toURLPlain()
{
return String.format("jdbc:%s://%s:%s/%s",
this.getDriver(),
this.getHost(),
this.getPort(),
this.getDatabase());
}
String getDriver(); String getDriver();
String getHost(); String getHost();
@ -27,27 +36,18 @@ public interface SQLProperties
String getDatabase(); String getDatabase();
String getUsername();
String getPassword();
default String toURLPlain()
{
return String.format("jdbc:%s://%s:%s/%s",
this.getDriver(),
this.getHost(),
this.getPort(),
this.getDatabase());
}
default String toURLWithLogin() default String toURLWithLogin()
{ {
return String.format("jdbc:%s://%s:%s/%s?user=%s&password=%s", return String.format("jdbc:%s://%s:%s/%s?user=%s&password=%s",
this.getDriver(), this.getDriver(),
this.getHost(), this.getHost(),
this.getPort(), this.getPort(),
this.getDatabase(), this.getDatabase(),
this.getUsername(), this.getUsername(),
this.getPassword()); this.getPassword());
} }
String getUsername();
String getPassword();
} }

View File

@ -1,12 +1,18 @@
package me.totalfreedom.user; package me.totalfreedom.user;
import me.totalfreedom.security.perm.PermissionHolder;
import me.totalfreedom.economy.EconomicEntity; import me.totalfreedom.economy.EconomicEntity;
import me.totalfreedom.economy.EconomicEntityData; import me.totalfreedom.economy.EconomicEntityData;
import me.totalfreedom.security.perm.PermissionHolder;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
public interface User extends PermissionHolder, EconomicEntity public interface User extends PermissionHolder, EconomicEntity
{ {
@Override
default EconomicEntityData getEconomicData()
{
return getUserData();
}
// Implement a few EconomicEntity methods in the User interface // Implement a few EconomicEntity methods in the User interface
@Override @Override
default String getName() default String getName()
@ -14,12 +20,6 @@ public interface User extends PermissionHolder, EconomicEntity
return getUserData().getUsername(); return getUserData().getUsername();
} }
@Override
default EconomicEntityData getEconomicData()
{
return getUserData();
}
UserData getUserData(); UserData getUserData();
Component getDisplayName(); Component getDisplayName();

View File

@ -1,7 +1,7 @@
package me.totalfreedom.user; package me.totalfreedom.user;
import me.totalfreedom.security.perm.Group;
import me.totalfreedom.economy.EconomicEntityData; import me.totalfreedom.economy.EconomicEntityData;
import me.totalfreedom.security.perm.Group;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@ -6,27 +6,29 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* This class contains the only reference to plain text component serializer, and allows access to it via wrapper functions. * This class contains the only reference to plain text component serializer, and allows access to it via wrapper
* functions.
*/ */
public class FreedomAdventure public class FreedomAdventure
{ {
private static final PlainTextComponentSerializer PLAIN_TEXT_COMPONENT_SERIALIZER =
PlainTextComponentSerializer.plainText();
private FreedomAdventure() private FreedomAdventure()
{ {
throw new UnsupportedOperationException("Instantiation of a static utility class is not supported."); throw new UnsupportedOperationException("Instantiation of a static utility class is not supported.");
} }
private static final PlainTextComponentSerializer PLAIN_TEXT_COMPONENT_SERIALIZER = PlainTextComponentSerializer.plainText(); public static String toPlainText(final Supplier<Component> supplier)
{
return toPlainText(supplier.get());
}
public static String toPlainText(final Component component) public static String toPlainText(final Component component)
{ {
return PLAIN_TEXT_COMPONENT_SERIALIZER.serialize(component); return PLAIN_TEXT_COMPONENT_SERIALIZER.serialize(component);
} }
public static String toPlainText(final Supplier<Component> supplier)
{
return toPlainText(supplier.get());
}
public static Supplier<String> supplyPlainText(final Supplier<Component> supplier) public static Supplier<String> supplyPlainText(final Supplier<Component> supplier)
{ {
return new StringRepresentationSupplier(supplier.get()); return new StringRepresentationSupplier(supplier.get());

View File

@ -31,30 +31,6 @@ public class FreedomLogger implements Audience
this.debug = debug; this.debug = debug;
} }
/**
* This method allows you to log a message to the console.
*
* @param message The message to send.
*/
public void info(final String message)
{
logger.info(message);
}
/**
* This method allows you to log a component to the console.
*
* @param component The component to send.
* @return A plain text representation of the message
*/
public String infoComponent(final Component component)
{
final String plainText = FreedomAdventure.toPlainText(component);
logger.info(plainText);
return plainText;
}
/** /**
* This method allows you to log a message to the console, * This method allows you to log a message to the console,
* while also returning a Component that could be used to * while also returning a Component that could be used to
@ -80,6 +56,28 @@ public class FreedomLogger implements Audience
public String infoComponent(final Supplier<Component> component) public String infoComponent(final Supplier<Component> component)
{ {
return this.infoComponent(component.get()); return this.infoComponent(component.get());
} /**
* This method allows you to log a message to the console.
*
* @param message The message to send.
*/
public void info(final String message)
{
logger.info(message);
}
/**
* This method allows you to log a component to the console.
*
* @param component The component to send.
* @return A plain text representation of the message
*/
public String infoComponent(final Component component)
{
final String plainText = FreedomAdventure.toPlainText(component);
logger.info(plainText);
return plainText;
} }
/** /**
@ -116,20 +114,6 @@ public class FreedomLogger implements Audience
logger.error(message); logger.error(message);
} }
/**
* This method logs an error component to the console.
*
* @param component The message to send.
*/
public String errorComponent(final Component component)
{
final String plainText = FreedomAdventure.toPlainText(component);
logger.error(plainText);
return plainText;
}
/** /**
* This method allows you to log an exception directly to the console. * This method allows you to log an exception directly to the console.
* *
@ -170,28 +154,15 @@ public class FreedomLogger implements Audience
} }
/** /**
* This method allows you to log a debug message to the console. * This method logs an error component to the console.
* This method will only log if debug mode is enabled.
* *
* @param message The message to send. * @param component The message to send.
*/ */
public void debug(final String message) public String errorComponent(final Component component)
{
if (debug)
logger.debug(message);
}
/**
* This method allows you to log a debug component to the console.
* This method will only log if debug mode is enabled.
*
* @param component The component to send.
*/
public String debugComponent(final Component component)
{ {
final String plainText = FreedomAdventure.toPlainText(component); final String plainText = FreedomAdventure.toPlainText(component);
this.debug(plainText); logger.error(plainText);
return plainText; return plainText;
} }
@ -231,6 +202,35 @@ public class FreedomLogger implements Audience
return ""; return "";
} }
/**
* This method allows you to log a debug component to the console.
* This method will only log if debug mode is enabled.
*
* @param component The component to send.
*/
public String debugComponent(final Component component)
{
final String plainText = FreedomAdventure.toPlainText(component);
this.debug(plainText);
return plainText;
}
/**
* This method allows you to log a debug message to the console.
* This method will only log if debug mode is enabled.
*
* @param message The message to send.
*/
public void debug(final String message)
{
if (debug)
logger.debug(message);
}
@Override @Override
public void sendMessage(@NotNull final ComponentLike message) public void sendMessage(@NotNull final ComponentLike message)
@ -267,6 +267,9 @@ public class FreedomLogger implements Audience
@Override @Override
public void sendMessage(@NotNull final SignedMessage signedMessage, final ChatType.@NotNull Bound boundChatType) public void sendMessage(@NotNull final SignedMessage signedMessage, final ChatType.@NotNull Bound boundChatType)
{ {
this.info(signedMessage.message()); // TODO: We might want to investigate whether this logs the ENTIRE message, including unsigned & signed content, or only the signed part. This method was written in the assumption that it provided all content. this.info(
signedMessage.message()); // TODO: We might want to investigate whether this logs the ENTIRE message,
// including unsigned & signed content, or only the signed part. This method was written in the assumption
// that it provided all content.
} }
} }

View File

@ -9,7 +9,8 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
/** /**
* This class contains different methods to provide {@link ChatType.Bound} instances for sending messages to players in game. * This class contains different methods to provide {@link ChatType.Bound} instances for sending messages to players
* in game.
* This is now a requirement for all message requests to players due to the new chat signature system. * This is now a requirement for all message requests to players due to the new chat signature system.
* <br> * <br>
* Even though Scissors has this feature disabled, upstream (Paper) and Kyori Adventure * Even though Scissors has this feature disabled, upstream (Paper) and Kyori Adventure
@ -30,13 +31,6 @@ public final class KyoriConstants
{ {
} }
public static ChatType.Bound fromPlugin(final JavaPlugin plugin)
{
final String name = plugin.getName();
final Component component = Component.text(name, NamedTextColor.GOLD);
return type.bind(component);
}
/** /**
* Represents a Chat Bound for a plugin. * Represents a Chat Bound for a plugin.
* <br> * <br>
@ -53,6 +47,13 @@ public final class KyoriConstants
return fromPlugin(plugin); return fromPlugin(plugin);
} }
public static ChatType.Bound fromPlugin(final JavaPlugin plugin)
{
final String name = plugin.getName();
final Component component = Component.text(name, NamedTextColor.GOLD);
return type.bind(component);
}
/** /**
* Represents a Chat Bound for a player. * Represents a Chat Bound for a player.
* Chat bounds are required for sending messages to players. * Chat bounds are required for sending messages to players.
@ -73,6 +74,7 @@ public final class KyoriConstants
* <br> * <br>
* The chat bound is a representation of a validated chat signature, * The chat bound is a representation of a validated chat signature,
* which is tied directly to the user's account name. In our case, this is the player's name. * which is tied directly to the user's account name. In our case, this is the player's name.
*
* @param sender The console to get the bound for. * @param sender The console to get the bound for.
* @return A ChatType.Bound instance for the console. * @return A ChatType.Bound instance for the console.
*/ */

View File

@ -20,7 +20,8 @@ public class Shaper
this.world = world; this.world = world;
} }
public List<Location> generate(final int count, final DoubleUnaryOperator x, final DoubleUnaryOperator y, final DoubleUnaryOperator z) public List<Location> generate(final int count, final DoubleUnaryOperator x, final DoubleUnaryOperator y,
final DoubleUnaryOperator z)
{ {
final double step = (start - end) / (count - 1); final double step = (start - end) / (count - 1);
final LinkedList<Location> lset = new LinkedList<>(); final LinkedList<Location> lset = new LinkedList<>();

View File

@ -1,17 +1,27 @@
[Google GSON]: https://github.com/google/gson "Google GSON" [Google GSON]: https://github.com/google/gson "Google GSON"
[Jetbrains Annotations]: https://github.com/JetBrains/JetBrains.Annotations "JetBrains Annotations" [Jetbrains Annotations]: https://github.com/JetBrains/JetBrains.Annotations "JetBrains Annotations"
[Lombok]: https://github.com/projectlombok/lombok "Lombok" [Lombok]: https://github.com/projectlombok/lombok "Lombok"
[Apache Commons]: https://github.com/apache/commons-lang "Apache Commons" [Apache Commons]: https://github.com/apache/commons-lang "Apache Commons"
[SLF4J]: https://github.com/qos-ch/slf4j "SLF4J" [SLF4J]: https://github.com/qos-ch/slf4j "SLF4J"
[Paper]: https://github.com/PaperMC/Paper "Paper" [Paper]: https://github.com/PaperMC/Paper "Paper"
[Kyori Adventure]: https://github.com/KyoriPowered/adventure "Kyori Adventure" [Kyori Adventure]: https://github.com/KyoriPowered/adventure "Kyori Adventure"
[Reflections API]: https://github.com/ronmamo/reflections "Reflections API" [Reflections API]: https://github.com/ronmamo/reflections "Reflections API"
[TotalFreedomMod]: https://github.com/AtlasMediaGroup/TotalFreedomMod "TotalFreedomMod" [TotalFreedomMod]: https://github.com/AtlasMediaGroup/TotalFreedomMod "TotalFreedomMod"
##### #####
![Header Image](https://media.discordapp.net/attachments/436759124953399296/1107175759941996544/20230514_002037_0000.png) ![Header Image](https://media.discordapp.net/attachments/436759124953399296/1107175759941996544/20230514_002037_0000.png)
### ###
[<img src="https://img.shields.io/static/v1?label=%20&message=Help%20Wanted&color=red&style=for-the-badge">](https://discord.gg/4PdtmrVNRx) [<img src="https://img.shields.io/static/v1?label=%20&message=Help%20Wanted&color=red&style=for-the-badge">](https://discord.gg/4PdtmrVNRx)
![GitHub contributors](https://img.shields.io/github/contributors/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge) ![GitHub contributors](https://img.shields.io/github/contributors/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge)
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge)
@ -21,6 +31,7 @@
![Codacy grade](https://img.shields.io/codacy/grade/7a0fa4694878444dabc6cc2804fbf125?style=for-the-badge) ![Codacy grade](https://img.shields.io/codacy/grade/7a0fa4694878444dabc6cc2804fbf125?style=for-the-badge)
### ###
[<img src="https://img.shields.io/static/v1?label=Roadmap&message=Google%20Docs&color=4285F4&style=for-the-badge&logo=googledrive">](https://docs.google.com/document/d/197fwNo076RsCiPW6e6QWaGEzTGnDcRuf5FBA6lNeiPE) [<img src="https://img.shields.io/static/v1?label=Roadmap&message=Google%20Docs&color=4285F4&style=for-the-badge&logo=googledrive">](https://docs.google.com/document/d/197fwNo076RsCiPW6e6QWaGEzTGnDcRuf5FBA6lNeiPE)
[<img src="https://img.shields.io/github/license/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge">](https://github.com/SimplexDevelopment/FreedomNetworkSuite/blob/kitchen-sink/LICENSE.md) [<img src="https://img.shields.io/github/license/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge">](https://github.com/SimplexDevelopment/FreedomNetworkSuite/blob/kitchen-sink/LICENSE.md)
![GitHub top language](https://img.shields.io/github/languages/top/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge&logo=github) ![GitHub top language](https://img.shields.io/github/languages/top/SimplexDevelopment/FreedomNetworkSuite?style=for-the-badge&logo=github)
@ -40,16 +51,18 @@ Honorable mention:
[<img src="https://img.shields.io/static/v1?label=Plex&message=A%20New%20Freedom%20Plugin&color=4285F4&style=flat-square&logo=plex)">](https://github.com/plexusorg/Plex) [<img src="https://img.shields.io/static/v1?label=Plex&message=A%20New%20Freedom%20Plugin&color=4285F4&style=flat-square&logo=plex)">](https://github.com/plexusorg/Plex)
This proof-of-concept also uses the following libraries: This proof-of-concept also uses the following libraries:
- [Google GSON] for Json interpretation
- [Jetbrains Annotations] for additional compiler annotations - [Google GSON] for Json interpretation
- [Lombok] for boilerplate generation - [Jetbrains Annotations] for additional compiler annotations
- [Apache Commons] for various utilities - [Lombok] for boilerplate generation
- [SLF4J] for logging - [Apache Commons] for various utilities
- [Paper] for the server implementation - [SLF4J] for logging
- [Kyori Adventure] for chat formatting - [Paper] for the server implementation
- [Reflections API] for reflections - [Kyori Adventure] for chat formatting
- [Reflections API] for reflections
# Developers # Developers
[<img src="https://img.shields.io/static/v1?label=Developer&message=Patches&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/Paldiu) [<img src="https://img.shields.io/static/v1?label=Developer&message=Patches&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/Paldiu)
<br /> <br />
[<img src="https://img.shields.io/static/v1?label=Developer&message=Video&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/VideoGameSmash12) [<img src="https://img.shields.io/static/v1?label=Developer&message=Video&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/VideoGameSmash12)
@ -57,7 +70,9 @@ This proof-of-concept also uses the following libraries:
[<img src="https://img.shields.io/static/v1?label=Developer&message=Allink&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/allinkdev) [<img src="https://img.shields.io/static/v1?label=Developer&message=Allink&color=blueviolet&style=for-the-badge&logo=intellijidea">](https://github.com/allinkdev)
# To Do List # To Do List
Patchwork: Patchwork:
- [x] Logging System - [x] Logging System
- [x] SQL API - [x] SQL API
- [x] Economy API - [x] Economy API
@ -72,6 +87,7 @@ Patchwork:
- [ ] Event API - [ ] Event API
Datura: Datura:
- [ ] Permission Handling - [ ] Permission Handling
- [ ] Permission Registration & Assignment - [ ] Permission Registration & Assignment
- [ ] SQL Data Handling - [ ] SQL Data Handling
@ -81,6 +97,7 @@ Datura:
- [ ] Punishment Systems (e.x. Locker, Halter, Muter, Cager) - [ ] Punishment Systems (e.x. Locker, Halter, Muter, Cager)
Fossil: Fossil:
- [x] Economy Implementation - [x] Economy Implementation
- [ ] Particle Implementation / Trails - [ ] Particle Implementation / Trails
- [ ] Command Implementations - [ ] Command Implementations
@ -89,6 +106,7 @@ Fossil:
- [ ] Jumppads - [ ] Jumppads
Corvo: Corvo:
- [ ] Service Implementation - [ ] Service Implementation
- [ ] Service Handling - [ ] Service Handling
- [ ] Task Implementation - [ ] Task Implementation