From f278ec17d400efe33649a45222fe5eea71fa243e Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Sat, 13 May 2023 22:08:26 -0500 Subject: [PATCH] Implementation Updates --- .../me/totalfreedom/base/CommonsBase.java | 28 +-- .../me/totalfreedom/base/Registration.java | 7 + .../me/totalfreedom/data/GroupRegistry.java | 40 ++++ .../me/totalfreedom/data/ServiceRegistry.java | 6 + .../me/totalfreedom/data/UserRegistry.java | 32 +++ .../java/me/totalfreedom/event/Callback.java | 7 + .../java/me/totalfreedom/event/EventBus.java | 78 +++---- .../totalfreedom/event/EventSubscription.java | 36 ++++ .../java/me/totalfreedom/event/FEvent.java | 18 +- .../java/me/totalfreedom/event/Handler.java | 10 - .../totalfreedom/event/SubscriptionBox.java | 25 +++ .../totalfreedom/service/FreedomExecutor.java | 58 +++++ .../java/me/totalfreedom/service/Service.java | 35 ++- .../main/java/me/totalfreedom/user/User.java | 2 + .../java/me/totalfreedom/user/UserData.java | 40 ++++ .../java/me/totalfreedom/utils/Shaper.java | 40 ++++ .../java/me/totalfreedom/datura/Datura.java | 21 ++ .../datura/perms/FreedomUser.java | 34 ++- .../totalfreedom/datura/punishment/Cager.java | 166 +++++++++++++++ .../datura/punishment/Halter.java | 33 +++ .../datura/punishment/Locker.java | 77 +++++++ .../datura/user/SimpleUserData.java | 200 ++++++++++++++++++ build.gradle | 1 - 23 files changed, 917 insertions(+), 77 deletions(-) create mode 100644 Commons/src/main/java/me/totalfreedom/data/GroupRegistry.java create mode 100644 Commons/src/main/java/me/totalfreedom/event/Callback.java create mode 100644 Commons/src/main/java/me/totalfreedom/event/EventSubscription.java delete mode 100644 Commons/src/main/java/me/totalfreedom/event/Handler.java create mode 100644 Commons/src/main/java/me/totalfreedom/event/SubscriptionBox.java create mode 100644 Commons/src/main/java/me/totalfreedom/service/FreedomExecutor.java create mode 100644 Commons/src/main/java/me/totalfreedom/user/UserData.java create mode 100644 Commons/src/main/java/me/totalfreedom/utils/Shaper.java create mode 100644 Datura/src/main/java/me/totalfreedom/datura/punishment/Cager.java create mode 100644 Datura/src/main/java/me/totalfreedom/datura/punishment/Halter.java create mode 100644 Datura/src/main/java/me/totalfreedom/datura/punishment/Locker.java create mode 100644 Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java diff --git a/Commons/src/main/java/me/totalfreedom/base/CommonsBase.java b/Commons/src/main/java/me/totalfreedom/base/CommonsBase.java index 22f449b..5e8fc94 100644 --- a/Commons/src/main/java/me/totalfreedom/base/CommonsBase.java +++ b/Commons/src/main/java/me/totalfreedom/base/CommonsBase.java @@ -1,15 +1,14 @@ package me.totalfreedom.base; import me.totalfreedom.event.EventBus; -import org.bukkit.Bukkit; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; +import me.totalfreedom.service.FreedomExecutor; import org.bukkit.plugin.java.JavaPlugin; public class CommonsBase extends JavaPlugin { private final EventBus eventBus = new EventBus(this); private final Registration registration = new Registration(); + private final FreedomExecutor executor = new FreedomExecutor(); public static CommonsBase getInstance() { @@ -19,24 +18,27 @@ public class CommonsBase extends JavaPlugin @Override public void onEnable() { - Bukkit.getServicesManager().register(EventBus.class, - eventBus, - this, - ServicePriority.High); + getRegistrations().getServiceRegistry().register(this, eventBus); + getExecutor().getSync() + .execute(() -> getRegistrations() + .getServiceRegistry() + .startAll()); } @Override public void onDisable() { - + getRegistrations().getServiceRegistry().stopAll(); + getRegistrations().getServiceRegistry().unregister(EventBus.class, eventBus); } - public RegisteredServiceProvider getEventBus() + public Registration getRegistrations() { - return Bukkit.getServicesManager().getRegistration(EventBus.class); - } - - public Registration getRegistrations() { return registration; } + + public FreedomExecutor getExecutor() + { + return executor; + } } diff --git a/Commons/src/main/java/me/totalfreedom/base/Registration.java b/Commons/src/main/java/me/totalfreedom/base/Registration.java index 73777aa..90e0b93 100644 --- a/Commons/src/main/java/me/totalfreedom/base/Registration.java +++ b/Commons/src/main/java/me/totalfreedom/base/Registration.java @@ -9,6 +9,7 @@ public class Registration private final UserRegistry userRegistry; private final ServiceRegistry serviceRegistry; private final ModuleRegistry moduleRegistry; + private final GroupRegistry groupRegistry; public Registration() { @@ -17,6 +18,7 @@ public class Registration this.userRegistry = new UserRegistry(); this.serviceRegistry = new ServiceRegistry(); this.moduleRegistry = new ModuleRegistry(); + this.groupRegistry = new GroupRegistry(); } public ModuleRegistry getModuleRegistry() @@ -43,4 +45,9 @@ public class Registration { return serviceRegistry; } + + public GroupRegistry getGroupRegistry() + { + return groupRegistry; + } } diff --git a/Commons/src/main/java/me/totalfreedom/data/GroupRegistry.java b/Commons/src/main/java/me/totalfreedom/data/GroupRegistry.java new file mode 100644 index 0000000..74d4c6e --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/data/GroupRegistry.java @@ -0,0 +1,40 @@ +package me.totalfreedom.data; + +import me.totalfreedom.security.Group; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; + +import java.util.ArrayList; +import java.util.List; + +public class GroupRegistry +{ + private final List groups; + + public GroupRegistry() + { + this.groups = new ArrayList<>(); + } + + public boolean registerGroup(Group group) { + return groups.add(group); + } + + public boolean unregisterGroup(Group group) { + return groups.remove(group); + } + + public Group getGroup(String name) { + PlainTextComponentSerializer s = PlainTextComponentSerializer.plainText(); + for (Group group : groups) { + String n = s.serialize(group.getName()); + if (n.equalsIgnoreCase(name)) { + return group; + } + } + return null; + } + + public List getGroups() { + return groups; + } +} diff --git a/Commons/src/main/java/me/totalfreedom/data/ServiceRegistry.java b/Commons/src/main/java/me/totalfreedom/data/ServiceRegistry.java index fd157ed..c91e4d6 100644 --- a/Commons/src/main/java/me/totalfreedom/data/ServiceRegistry.java +++ b/Commons/src/main/java/me/totalfreedom/data/ServiceRegistry.java @@ -61,4 +61,10 @@ public class ServiceRegistry { return Bukkit.getServicesManager().getRegistration(clazz); } + + public void unregister(Class clazz, Service service) + { + this.services.remove(service); + Bukkit.getServicesManager().unregister(clazz, service); + } } diff --git a/Commons/src/main/java/me/totalfreedom/data/UserRegistry.java b/Commons/src/main/java/me/totalfreedom/data/UserRegistry.java index b84e179..89fe42a 100644 --- a/Commons/src/main/java/me/totalfreedom/data/UserRegistry.java +++ b/Commons/src/main/java/me/totalfreedom/data/UserRegistry.java @@ -1,5 +1,37 @@ package me.totalfreedom.data; +import me.totalfreedom.user.User; +import me.totalfreedom.user.UserData; + +import java.util.HashMap; +import java.util.Map; + public class UserRegistry { + private final Map userDataMap; + + public UserRegistry() + { + this.userDataMap = new HashMap<>(); + } + + public UserData getUserData(User user) + { + return userDataMap.get(user); + } + + public void registerUserData(User user, UserData userData) + { + userDataMap.put(user, userData); + } + + public void unregisterUserData(User user) + { + userDataMap.remove(user); + } + + public Map getUserDataMap() + { + return userDataMap; + } } diff --git a/Commons/src/main/java/me/totalfreedom/event/Callback.java b/Commons/src/main/java/me/totalfreedom/event/Callback.java new file mode 100644 index 0000000..585d144 --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/event/Callback.java @@ -0,0 +1,7 @@ +package me.totalfreedom.event; + +@FunctionalInterface +public interface Callback +{ + void call(T event); +} diff --git a/Commons/src/main/java/me/totalfreedom/event/EventBus.java b/Commons/src/main/java/me/totalfreedom/event/EventBus.java index 918dea8..1333b71 100644 --- a/Commons/src/main/java/me/totalfreedom/event/EventBus.java +++ b/Commons/src/main/java/me/totalfreedom/event/EventBus.java @@ -1,74 +1,58 @@ package me.totalfreedom.event; +import me.totalfreedom.api.Context; import me.totalfreedom.base.CommonsBase; -import org.bukkit.event.Listener; +import me.totalfreedom.service.Service; -import java.lang.reflect.Executable; -import java.util.*; -import java.util.stream.Collectors; +import java.util.HashSet; +import java.util.Set; -public class EventBus +public class EventBus extends Service { - private final Set listenerSet = new HashSet<>(); - private final Map> listenerEventMap = new HashMap<>(); private final CommonsBase plugin; + private final Set eventSet = new HashSet<>(); + private final SubscriptionBox runningSubscriptions = new SubscriptionBox<>(); public EventBus(CommonsBase plugin) { + super("event_bus"); this.plugin = plugin; } - void registerListener(Listener listener) + public void addEvent(FEvent event) { - Set eventSet = Arrays.stream(listener.getClass().getDeclaredMethods()) - .filter(m -> m.isAnnotationPresent(Handler.class)) - .map(Executable::getParameters) - .filter(p -> p.length == 1) - .filter(p -> FEvent.class.isAssignableFrom(p[0].getType())) - .map(p -> - { - try - { - return (FEvent) p[0].getType().getDeclaredConstructor().newInstance(); - } catch (Exception exception) - { - exception.printStackTrace(); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - - listenerEventMap.put(listener, eventSet); + eventSet.add(event); } - void unregisterListener(Listener listener) + public EventSubscription subscribe(Class eventClass, Callback callback) { - listenerEventMap.remove(listener); + Context eventContext = () -> eventSet.stream() + .filter(event -> event.getEventClass().equals(eventClass)) + .findFirst() + .map(eventClass::cast) + .orElse(null); + + if (eventContext.get() == null) + { + throw new IllegalArgumentException("Event class " + eventClass.getName() + " is not registered."); + } + + return new EventSubscription<>(eventContext.get(), callback); } - public void startListening() + public void unsubscribe(EventSubscription subscription) { - listenerSet().forEach(this::registerListener); - } - - public void stopListening() - { - listenerSet().forEach(this::unregisterListener); - } - - public Set listenerSet() - { - return listenerSet; - } - - public Map> listenerEventMap() - { - return listenerEventMap; + runningSubscriptions.removeSubscription(subscription); } public CommonsBase getCommonsBase() { return plugin; } + + @Override + public void tick() + { + runningSubscriptions.tick(); + } } diff --git a/Commons/src/main/java/me/totalfreedom/event/EventSubscription.java b/Commons/src/main/java/me/totalfreedom/event/EventSubscription.java new file mode 100644 index 0000000..0915187 --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/event/EventSubscription.java @@ -0,0 +1,36 @@ +package me.totalfreedom.event; + +import me.totalfreedom.api.Context; + +import java.util.function.Supplier; + +public final class EventSubscription +{ + private final T event; + private final Callback callback; + + public EventSubscription(T event, Callback callback) + { + this.event = event; + this.callback = callback; + } + + public T getEvent() + { + return event; + } + + public boolean cancel() + { + return getEvent().cancel(); + } + + public boolean isCancelled() + { + return getEvent().isCancelled(); + } + + public Callback getCallback() { + return callback; + } +} diff --git a/Commons/src/main/java/me/totalfreedom/event/FEvent.java b/Commons/src/main/java/me/totalfreedom/event/FEvent.java index 418d1a4..0889d7b 100644 --- a/Commons/src/main/java/me/totalfreedom/event/FEvent.java +++ b/Commons/src/main/java/me/totalfreedom/event/FEvent.java @@ -4,11 +4,25 @@ import me.totalfreedom.api.Context; public abstract class FEvent { + private boolean isCancelled; + protected FEvent() { + this.isCancelled = false; } - public abstract void call(Context... contexts); + public abstract void call(Callback callback); - public abstract void cancel(); + public boolean cancel() + { + this.isCancelled = true; + return isCancelled(); + } + + public boolean isCancelled() + { + return isCancelled; + } + + public abstract Class getEventClass(); } diff --git a/Commons/src/main/java/me/totalfreedom/event/Handler.java b/Commons/src/main/java/me/totalfreedom/event/Handler.java deleted file mode 100644 index 3bd664e..0000000 --- a/Commons/src/main/java/me/totalfreedom/event/Handler.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.totalfreedom.event; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface Handler -{ - // This is a marker annotation -} diff --git a/Commons/src/main/java/me/totalfreedom/event/SubscriptionBox.java b/Commons/src/main/java/me/totalfreedom/event/SubscriptionBox.java new file mode 100644 index 0000000..c55325e --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/event/SubscriptionBox.java @@ -0,0 +1,25 @@ +package me.totalfreedom.event; + +import java.util.ArrayList; +import java.util.List; + +class SubscriptionBox +{ + private final List> subscriptions; + + public SubscriptionBox() { + this.subscriptions = new ArrayList<>(); + } + + public void addSubscription(EventSubscription subscription) { + subscriptions.add(subscription); + } + + public void removeSubscription(EventSubscription subscription) { + subscriptions.remove(subscription); + } + + public void tick() { + subscriptions.forEach(s -> s.getCallback().call(s.getEvent())); + } +} diff --git a/Commons/src/main/java/me/totalfreedom/service/FreedomExecutor.java b/Commons/src/main/java/me/totalfreedom/service/FreedomExecutor.java new file mode 100644 index 0000000..e26451a --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/service/FreedomExecutor.java @@ -0,0 +1,58 @@ +package me.totalfreedom.service; + +import me.totalfreedom.base.CommonsBase; +import org.bukkit.Bukkit; + +import java.util.concurrent.Executor; + +public class FreedomExecutor +{ + private final Executor syncExecutor; + private final Executor asyncExecutor; + + public FreedomExecutor() + { + syncExecutor = r -> Bukkit.getScheduler().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(long delay, long period) + { + return r -> Bukkit.getScheduler() + .runTaskTimer( + CommonsBase.getInstance(), + r, + delay, + period); + } + + public Executor scheduledAsync(long delay, long period) + { + return r -> Bukkit.getScheduler() + .runTaskTimerAsynchronously( + CommonsBase.getInstance(), + r, + delay, + period); + } + + public void runSync(Task task) + { + getSync().execute(task); + } + + public void runAsync(Task task) + { + getAsync().execute(task); + } +} diff --git a/Commons/src/main/java/me/totalfreedom/service/Service.java b/Commons/src/main/java/me/totalfreedom/service/Service.java index 7f2f6e2..54e83bd 100644 --- a/Commons/src/main/java/me/totalfreedom/service/Service.java +++ b/Commons/src/main/java/me/totalfreedom/service/Service.java @@ -1,8 +1,11 @@ package me.totalfreedom.service; +import me.totalfreedom.base.CommonsBase; + public abstract class Service { private final String name; + private boolean isActive = false; protected Service(String name) { @@ -10,7 +13,35 @@ public abstract class Service } - public abstract void start(); + public void start() + { + isActive = true; + CommonsBase.getInstance() + .getExecutor() + .getSync() + .execute(() -> + { + while (isActive) + { + tick(); + } + }); + } - public abstract void stop(); + public void stop() + { + isActive = false; + } + + public abstract void tick(); + + public String getName() + { + return name; + } + + public boolean isActive() + { + return isActive; + } } diff --git a/Commons/src/main/java/me/totalfreedom/user/User.java b/Commons/src/main/java/me/totalfreedom/user/User.java index 82cff23..222e2a9 100644 --- a/Commons/src/main/java/me/totalfreedom/user/User.java +++ b/Commons/src/main/java/me/totalfreedom/user/User.java @@ -5,6 +5,8 @@ import net.kyori.adventure.text.Component; public interface User extends PermissionHolder { + UserData getUserData(); + Component getDisplayName(); boolean isOnline(); diff --git a/Commons/src/main/java/me/totalfreedom/user/UserData.java b/Commons/src/main/java/me/totalfreedom/user/UserData.java new file mode 100644 index 0000000..ac2e277 --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/user/UserData.java @@ -0,0 +1,40 @@ +package me.totalfreedom.user; + +import me.totalfreedom.security.Group; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public interface UserData +{ + @NotNull UUID getUniqueId(); + + String getUsername(); + + User getUser(); + + @Nullable Group getGroup(); + + void setGroup(@Nullable Group group); + + long getPlaytime(); + + void setPlaytime(long playtime); + + void addPlaytime(long playtime); + + void resetPlaytime(); + + boolean isFrozen(); + + void setFrozen(boolean frozen); + + boolean canInteract(); + + void setInteractionState(boolean canInteract); + + boolean isCaged(); + + void setCaged(boolean caged); +} diff --git a/Commons/src/main/java/me/totalfreedom/utils/Shaper.java b/Commons/src/main/java/me/totalfreedom/utils/Shaper.java new file mode 100644 index 0000000..dbf9dd4 --- /dev/null +++ b/Commons/src/main/java/me/totalfreedom/utils/Shaper.java @@ -0,0 +1,40 @@ +package me.totalfreedom.utils; + +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.DoubleUnaryOperator; + +public class Shaper +{ + private final double start; + private final double end; + private final World world; + + public Shaper(World world, double start, double end) + { + this.start = start; + this.end = end; + this.world = world; + } + + public List generate(int count, DoubleUnaryOperator x, DoubleUnaryOperator y, DoubleUnaryOperator z) + { + double step = (start - end) / (count - 1); + LinkedList lset = new LinkedList<>(); + + for (int i = 0; i < count; i++) + { + double t = start + i * step; + double xp = x.applyAsDouble(t); + double yp = y.applyAsDouble(t); + double zp = z.applyAsDouble(t); + + lset.add(new Location(world, xp, yp, zp)); + } + + return lset; + } +} diff --git a/Datura/src/main/java/me/totalfreedom/datura/Datura.java b/Datura/src/main/java/me/totalfreedom/datura/Datura.java index bd5c8b0..e1006f6 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/Datura.java +++ b/Datura/src/main/java/me/totalfreedom/datura/Datura.java @@ -1,10 +1,21 @@ package me.totalfreedom.datura; import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.datura.punishment.Cager; +import me.totalfreedom.datura.punishment.Halter; +import me.totalfreedom.datura.punishment.Locker; +import me.totalfreedom.datura.sql.MySQL; +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; public class Datura extends JavaPlugin { + private final MySQL sql = new MySQL("localhost", 3011, "master"); + private final Halter halter = new Halter(); + private final Locker locker = new Locker(); + private final Cager cager = new Cager(); + + @Override public void onEnable() { @@ -12,5 +23,15 @@ public class Datura extends JavaPlugin .getRegistrations() .getModuleRegistry() .addModule(this); + + CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, locker); + CommonsBase.getInstance().getRegistrations().getServiceRegistry().register(this, cager); + + Bukkit.getPluginManager().registerEvents(halter, this); + } + + public MySQL getSQL() + { + return sql; } } diff --git a/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomUser.java b/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomUser.java index 6de1239..c1c30af 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomUser.java +++ b/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomUser.java @@ -1,8 +1,11 @@ package me.totalfreedom.datura.perms; import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.datura.Datura; +import me.totalfreedom.datura.user.SimpleUserData; import me.totalfreedom.security.Node; import me.totalfreedom.user.User; +import me.totalfreedom.user.UserData; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -27,6 +30,7 @@ public class FreedomUser implements User private final Map bukkitAttachments = new HashMap<>(); private final Component displayName; private final String NOT_ONLINE = "Player is not online"; + private final UserData userData; public FreedomUser(Player player) { @@ -34,6 +38,30 @@ public class FreedomUser implements User this.permissions = new HashSet<>(); this.displayName = player.displayName(); + Datura datura = CommonsBase.getInstance() + .getRegistrations() + .getModuleRegistry() + .getModule(Datura.class) + .getModule(); + + UserData data = SimpleUserData.fromSQL(datura.getSQL(), uuid.toString()); + + if (data == null) + { + data = new SimpleUserData(player); + } + + this.userData = data; + + CommonsBase.getInstance() + .getRegistrations() + .getUserRegistry() + .registerUserData(this, userData); + } + + @Override + public UserData getUserData() { + return userData; } @Override @@ -197,9 +225,11 @@ public class FreedomUser implements User @Override public void setOp(boolean value) { - if (value) { + if (value) + { permissions().add(DefaultNodes.OP); - } else { + } else + { permissions().remove(DefaultNodes.OP); } } diff --git a/Datura/src/main/java/me/totalfreedom/datura/punishment/Cager.java b/Datura/src/main/java/me/totalfreedom/datura/punishment/Cager.java new file mode 100644 index 0000000..332e169 --- /dev/null +++ b/Datura/src/main/java/me/totalfreedom/datura/punishment/Cager.java @@ -0,0 +1,166 @@ +package me.totalfreedom.datura.punishment; + +import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.service.Service; +import me.totalfreedom.utils.Shaper; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.*; +import java.util.function.DoubleUnaryOperator; + +public class Cager extends Service +{ + private final Set cagedPlayers; + private final Map cageLocations; + + public Cager() + { + super("cage_service"); + this.cagedPlayers = new HashSet<>(); + this.cageLocations = new HashMap<>(); + Bukkit.getPluginManager().registerEvents(new CageListener(), CommonsBase.getInstance()); + } + + /** + * This method will cage the player using {@link #createCage(Location, Material)}. + *

This will also add the returned location to the {@link #cageLocations} map. + * + * @param uuid The UUID of the player to cage. + */ + public void cagePlayer(UUID uuid) + { + Player player = Bukkit.getPlayer(uuid); + if (player == null) return; + + cagedPlayers.add(uuid); + cageLocations.put(uuid, createCage(player.getLocation(), Material.GLASS)); + } + + public void cagePlayer(UUID uuid, Material material) + { + Player player = Bukkit.getPlayer(uuid); + if (player == null) return; + + cagedPlayers.add(uuid); + cageLocations.put(uuid, createCage(player.getLocation(), material)); + } + + /** + * This method will uncage the player by removing them from the {@link #cagedPlayers} set. + * + * @param uuid The UUID of the player to uncage. + */ + public void uncagePlayer(UUID uuid) + { + cagedPlayers.remove(uuid); + Location location = cageLocations.get(uuid); + + createCage(location, Material.AIR); // Remove the cage (set all blocks to air). + + cageLocations.remove(uuid); + } + + /** + * This method will check to make sure each caged player remains within their cage. + * We use + *

+ * {@link Location#distanceSquared(Location)} * {@link Math#pow(double, double)} + *

+ * to check if the player is outside the cage. + */ + @Override + public void tick() + { + for (UUID uuid : cagedPlayers) + { + Player player = Bukkit.getPlayer(uuid); + if (player == null) continue; + + Location cageLocation = getCageLocation(player); + + final boolean inside; + if (!player.getWorld().equals(cageLocation.getWorld())) + { + inside = false; + } else + { + inside = player.getLocation().distanceSquared(cageLocation) > (Math.pow(2.5, 2.0)); + } + + if (!inside) + { + player.teleport(cageLocation); + } + } + } + + /** + * This method returns whether the player is caged. + *

This method requires the player to be online to execute properly.

+ * + * @param player The player to check. + * @return Whether the player is caged. + */ + public Location getCageLocation(Player player) + { + 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(Location location, Material material) + { + Shaper shaper = new Shaper(location.getWorld(), 0.0, 4.0); + List 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 (Location l : cubed) + { + location.getWorld().getBlockAt(l).setType(material); + } + + return location.clone(); // Return the passed location as that is the center of the cube. + } + + private final class CageListener implements Listener + { + @EventHandler + public void blockBreakEvent(BlockBreakEvent event) + { + if (cagedPlayers.contains(event.getPlayer().getUniqueId())) + { + event.setCancelled(true); + } + } + + @EventHandler + public void playerLeaveEvent(PlayerQuitEvent event) { + if (cagedPlayers.contains(event.getPlayer().getUniqueId())) + { + uncagePlayer(event.getPlayer().getUniqueId()); + } + } + } +} diff --git a/Datura/src/main/java/me/totalfreedom/datura/punishment/Halter.java b/Datura/src/main/java/me/totalfreedom/datura/punishment/Halter.java new file mode 100644 index 0000000..62051b5 --- /dev/null +++ b/Datura/src/main/java/me/totalfreedom/datura/punishment/Halter.java @@ -0,0 +1,33 @@ +package me.totalfreedom.datura.punishment; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class Halter implements Listener +{ + private final Set haltedPlayers; + + public Halter() + { + this.haltedPlayers = new HashSet<>(); + } + + public void halt(final UUID uuid) + { + this.haltedPlayers.add(uuid); + } + + @EventHandler + public void playerMove(PlayerMoveEvent event) + { + if (haltedPlayers.contains(event.getPlayer().getUniqueId())) + { + event.setCancelled(true); + } + } +} diff --git a/Datura/src/main/java/me/totalfreedom/datura/punishment/Locker.java b/Datura/src/main/java/me/totalfreedom/datura/punishment/Locker.java new file mode 100644 index 0000000..320e931 --- /dev/null +++ b/Datura/src/main/java/me/totalfreedom/datura/punishment/Locker.java @@ -0,0 +1,77 @@ +package me.totalfreedom.datura.punishment; + +import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.service.Service; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; +import java.util.SplittableRandom; +import java.util.UUID; + +public class Locker extends Service +{ + private final Set lockedPlayers = new HashSet<>(); + + public Locker() + { + super("locker-service"); + } + + public void lock(UUID uuid) + { + lockedPlayers.add(uuid); + } + + @Override + public void tick() + { + lockedPlayers.removeIf(uuid -> !CommonsBase.getInstance().getServer().getOfflinePlayer(uuid).isOnline()); + + for (UUID uuid : lockedPlayers) + { + Player player = Bukkit.getPlayer(uuid); + if (player == null) continue; + + lockingMethod(player); + } + } + + private void lockingMethod(@NotNull Player player) + { + double x = player.getLocation().getX(); + double z = player.getLocation().getZ(); + + if ((x / z % 0.001) < 1) + { + player.setVelocity(new Vector(x % 12, 0, z % 12)); + } + + player.setWalkSpeed(0.0f); + player.setFlySpeed(0.0f); + player.setAllowFlight(false); + player.setFlying(false); + player.setInvulnerable(true); + player.setCollidable(false); + player.setGliding(false); + player.setGlowing(true); + player.setSilent(true); + player.setCanPickupItems(false); + player.setInvisible(true); + + player.openInventory(Bukkit.createInventory(null, 54)); + player.closeInventory(InventoryCloseEvent.Reason.UNKNOWN); + player.teleport(player.getLocation().clone()); + + final SplittableRandom random = new SplittableRandom(); + player.getEyeLocation().add(new Vector( + random.nextDouble(-1.0, 1.0), + random.nextDouble(-1.0, 1.0), + random.nextDouble(-1.0, 1.0) + )); + } +} diff --git a/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java b/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java new file mode 100644 index 0000000..cb6db2a --- /dev/null +++ b/Datura/src/main/java/me/totalfreedom/datura/user/SimpleUserData.java @@ -0,0 +1,200 @@ +package me.totalfreedom.datura.user; + +import me.totalfreedom.base.CommonsBase; +import me.totalfreedom.datura.perms.FreedomUser; +import me.totalfreedom.security.Group; +import me.totalfreedom.sql.SQL; +import me.totalfreedom.user.User; +import me.totalfreedom.user.UserData; +import me.totalfreedom.utils.FreedomLogger; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.sql.SQLException; +import java.util.UUID; + +public class SimpleUserData implements UserData +{ + private final UUID uuid; + private final String username; + private final User user; + private Group group; + private long playtime; + private boolean frozen; + private boolean canInteract; + private boolean caged; + + public SimpleUserData(final Player player) + { + this.uuid = player.getUniqueId(); + this.username = player.getName(); + this.user = new FreedomUser(player); + } + + private SimpleUserData( + final UUID uuid, + final String username, + final User user, + final Group group, + final long playtime, + final boolean frozen, + final boolean canInteract, + final boolean caged) + { + this.uuid = uuid; + this.username = username; + this.user = user; + this.group = group; + this.playtime = playtime; + this.frozen = frozen; + this.canInteract = canInteract; + this.caged = caged; + } + + public static SimpleUserData fromSQL(SQL sql, String uuid) + { + return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid) + .thenApplyAsync(result -> + { + try + { + if (result.next()) + { + String g = result.getString("group"); + + UUID u = UUID.fromString(uuid); + String username = result.getString("username"); + + Player player = Bukkit.getPlayer(u); + + if (player == null) + throw new IllegalStateException("Player should be online but they are not!"); + + User user = new FreedomUser(player); + Group group = CommonsBase.getInstance() + .getRegistrations() + .getGroupRegistry() + .getGroup(g); + long playtime = result.getLong("playtime"); + boolean frozen = result.getBoolean("frozen"); + boolean canInteract = result.getBoolean("canInteract"); + boolean caged = result.getBoolean("caged"); + return new SimpleUserData(u, username, user, group, playtime, frozen, canInteract, caged); + } + } catch (SQLException ex) + { + StringBuilder sb = new StringBuilder(); + sb.append("An error occurred while trying to retrieve user data for UUID ") + .append(uuid) + .append(" from the database.") + .append("\nCaused by: ") + .append(ExceptionUtils.getRootCauseMessage(ex)) + .append("\nStack trace: ") + .append(ExceptionUtils.getStackTrace(ex)); + + FreedomLogger.getLogger("Datura") + .error(sb.toString()); + } + + Player player = Bukkit.getPlayer(UUID.fromString(uuid)); + if (player == null) throw new IllegalStateException("Player should be online but they are not!"); + return new SimpleUserData(player); + }, CommonsBase.getInstance() + .getExecutor() + .getAsync()) + .join(); + } + + @Override + public @NotNull UUID getUniqueId() + { + return uuid; + } + + @Override + public String getUsername() + { + return username; + } + + @Override + public User getUser() + { + return user; + } + + @Override + public @Nullable Group getGroup() + { + return group; + } + + @Override + public void setGroup(@Nullable Group group) + { + this.group = group; + } + + @Override + public long getPlaytime() + { + return playtime; + } + + @Override + public void setPlaytime(long playtime) + { + this.playtime = playtime; + } + + @Override + public void addPlaytime(long playtime) + { + this.playtime += playtime; + } + + @Override + public void resetPlaytime() + { + this.playtime = 0L; + } + + @Override + public boolean isFrozen() + { + return frozen; + } + + @Override + public void setFrozen(boolean frozen) + { + this.frozen = true; + } + + @Override + public boolean canInteract() + { + return canInteract; + } + + @Override + public void setInteractionState(boolean canInteract) + { + this.canInteract = canInteract; + } + + @Override + public boolean isCaged() + { + return caged; + } + + @Override + public void setCaged(boolean caged) + { + this.caged = caged; + } +} diff --git a/build.gradle b/build.gradle index 685e50a..4ad34a0 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,6 @@ subprojects { compileOnly 'org.apache.commons:commons-collections4:4.2' compileOnly 'com.google.guava:guava:31.1-jre' compileOnly 'com.google.code.gson:gson:2.8.8' - compileOnly 'io.projectreactor:reactor-core:3.5.4' compileOnly 'org.reflections:reflections:0.10.2' compileOnly 'org.slf4j:slf4j-api:1.7.36' compileOnly 'co.aikar:acf-paper:0.5.1-SNAPSHOT'