From 7de325e5246142dad59ffcfd035d39757518b003 Mon Sep 17 00:00:00 2001
From: Martin Hustoles <martin.hustoles@student.reutlingen-university.de>
Date: Sun, 8 Oct 2023 19:34:20 +0200
Subject: [PATCH] PixelCampusEssentials created

---
 .gitignore                                    | 113 ++++++
 pom.xml                                       |  84 +++++
 src/main/java/Plots/PlayerSelection.java      |  80 +++++
 src/main/java/Plots/Plots.java                | 330 ++++++++++++++++++
 src/main/java/Plots/PlotsTabComplete.java     |  52 +++
 .../PixelcampusEssentials.java                |  36 ++
 src/main/resources/config.yml                 |   2 +
 src/main/resources/plugin.yml                 |  10 +
 8 files changed, 707 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 pom.xml
 create mode 100644 src/main/java/Plots/PlayerSelection.java
 create mode 100644 src/main/java/Plots/Plots.java
 create mode 100644 src/main/java/Plots/PlotsTabComplete.java
 create mode 100644 src/main/java/fsi/pixelcampusessentials/PixelcampusEssentials.java
 create mode 100644 src/main/resources/config.yml
 create mode 100644 src/main/resources/plugin.yml

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4788b4b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,113 @@
+# User-specific stuff
+.idea/
+
+*.iml
+*.ipr
+*.iws
+
+# IntelliJ
+out/
+
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+target/
+
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+.flattened-pom.xml
+
+# Common working directory
+run/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..75e8712
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>FSI</groupId>
+    <artifactId>PixelcampusEssentials</artifactId>
+    <version>1.0</version>
+    <packaging>jar</packaging>
+
+    <name>PixelcampusEssentials</name>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>16</source>
+                    <target>16</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.2.4</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>sk89q-repo</id>
+            <url>https://maven.enginehub.org/repo/</url>
+        </repository>
+        <repository>
+            <id>papermc-repo</id>
+            <url>https://repo.papermc.io/repository/maven-public/</url>
+        </repository>
+        <repository>
+            <id>sonatype</id>
+            <url>https://oss.sonatype.org/content/groups/public/</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.sk89q.worldguard</groupId>
+            <artifactId>worldguard-bukkit</artifactId>
+            <version>7.0.9</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.papermc.paper</groupId>
+            <artifactId>paper-api</artifactId>
+            <version>1.20.1-R0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/Plots/PlayerSelection.java b/src/main/java/Plots/PlayerSelection.java
new file mode 100644
index 0000000..6e1689a
--- /dev/null
+++ b/src/main/java/Plots/PlayerSelection.java
@@ -0,0 +1,80 @@
+package Plots;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.util.BlockVector;
+import org.jetbrains.annotations.NotNull;
+
+public class PlayerSelection implements Listener {
+
+    @EventHandler
+    public void playerLeaveEvent(@NotNull PlayerQuitEvent e){
+        removeFromQeue(e.getPlayer());
+    }
+
+    private boolean removeFromQeue(Player p){
+
+        String uuidToRemove = p.getUniqueId().toString();
+
+        for (PlayerSelection i : Plots.getSelectionsQeue()) {
+            if (i.getUUID().equals(uuidToRemove)) {
+                Plots.getSelectionsQeue().remove(i);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static PlayerSelection getfromQeue(Player p){
+
+        String uuid = p.getUniqueId().toString();
+
+        for (PlayerSelection i : Plots.getSelectionsQeue()) {
+            if (i.getUUID().equals(uuid)) {
+                return i;
+            }
+        }
+
+        return null;
+    }
+
+    public PlayerSelection(){
+    }
+    public PlayerSelection(String UUID, BlockVector pos1, BlockVector pos2) {
+        this.UUID = UUID;
+        this.pos1 = pos1;
+        this.pos2 = pos2;
+    }
+
+    public void setUUID(String UUID) {
+        this.UUID = UUID;
+    }
+
+    public void setPos1(BlockVector pos1) {
+        this.pos1 = pos1;
+    }
+
+    public void setPos2(BlockVector pos2) {
+        this.pos2 = pos2;
+    }
+
+    public String getUUID() {
+        return UUID;
+    }
+
+    public BlockVector getPos1() {
+        return pos1;
+    }
+
+    public BlockVector getPos2() {
+        return pos2;
+    }
+
+    private String UUID = null;
+    private BlockVector pos1 = null;
+    private BlockVector pos2 = null;
+
+}
\ No newline at end of file
diff --git a/src/main/java/Plots/Plots.java b/src/main/java/Plots/Plots.java
new file mode 100644
index 0000000..3f44450
--- /dev/null
+++ b/src/main/java/Plots/Plots.java
@@ -0,0 +1,330 @@
+package Plots;
+
+import com.google.common.collect.Lists;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldguard.WorldGuard;
+import com.sk89q.worldguard.domains.DefaultDomain;
+import com.sk89q.worldguard.protection.ApplicableRegionSet;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+import com.sk89q.worldguard.protection.regions.RegionContainer;
+import fsi.pixelcampusessentials.PixelcampusEssentials;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.util.BlockVector;
+import org.bukkit.util.Vector;
+import org.checkerframework.checker.units.qual.A;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+public class Plots implements CommandExecutor, Listener {
+
+    private static final ArrayList<PlayerSelection> selectionsQeue = new ArrayList<>();
+    private static Integer MAX_PLOT_SIZE;
+    private static final String[] cmds = {"pos1","pos2","claim","unclaim","info","addmember","removemember"};
+
+    public Plots(){
+
+        try {
+            MAX_PLOT_SIZE = Integer.parseInt(String.valueOf(PixelcampusEssentials.getPlugin().getConfig().getList("maxPlotSize").get(0)));
+        }catch (Exception e){
+
+            //if the value from the config fails to load, set default MAX_PLOT_SIZE to 62500;
+            e.printStackTrace();
+            MAX_PLOT_SIZE = 62500;
+        }
+    }
+
+    @Override
+    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+
+        if(!(sender instanceof Player)){
+            sender.sendMessage("§cYou must be a Player to do this!");
+            return true;
+        }
+
+        Player p = (Player)sender;
+        int cmd;
+
+        try{
+            cmd = chosenCommand(args[0]);
+        }catch (Exception e){
+            return false;
+        }
+
+        if(cmd == -1){
+            return false;
+        }
+
+        if(!sender.hasPermission("suwupremeEssentials.plot")){
+            sender.sendMessage("§cYou dont have the nessecary Permissions to use Plots");
+            return true;
+        }
+
+        //fetching Player that will be added to the region
+        Player p2 = null;
+        if(cmd == 6 || cmd == 7){
+
+            try {
+                p2 = Bukkit.getPlayer(args[1]);
+                if(p2 == null)throw new Exception("§cPlayer " + args[1] + " not found! Player has to be online");
+
+            }catch (Exception e){
+                p.sendMessage(e.getMessage());
+                return true;
+            }
+        }
+
+
+        try {
+            switch (cmd) {
+                case 1 -> setPosition(p, 1);
+                case 2 -> setPosition(p, 2);
+                case 3 -> claimPlot(p);
+                case 4 -> unclaimPLot(p);
+                case 5 -> info(p, p.getWorld(), p.getLocation());
+                case 6 -> addMember(p, p2);
+                case 7 -> removeMember(p, p2);
+                default -> {
+                    return false;
+                }
+            }
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return true;
+        }
+
+        return true;
+    }
+
+    private void setPosition(Player p, Integer posNumber){
+
+        BlockVector playerPos = p.getLocation().toVector().toBlockVector();
+        PlayerSelection sel = PlayerSelection.getfromQeue(p);
+
+        //if player hasnt already started a selection
+        if(sel == null){
+
+            sel = new PlayerSelection(
+                    p.getUniqueId().toString(),
+                    posNumber == 1 ? playerPos : null,
+                    posNumber == 2 ? playerPos : null
+            );
+        }else{
+
+            if (posNumber == 1) {
+                sel.setPos1(playerPos);
+            } else {
+                sel.setPos2(playerPos);
+            }
+        }
+
+
+        selectionsQeue.add(sel);
+
+        p.sendMessage("§aPos " + posNumber + " set.");
+    }
+
+    private void claimPlot(Player p){
+
+        PlayerSelection sel = PlayerSelection.getfromQeue(p);
+
+        if(sel == null){
+            p.sendMessage("§cMake a Selection first using /plot [pos1,pos2]");
+            return;
+        }else{
+
+            if(sel.getPos1() == null){
+                p.sendMessage("§cPosition 1 is missing. Use /plot pos1");
+                return;
+            }else if(sel.getPos2() == null){
+                p.sendMessage("§cPosition 2 is missing. Use /plot pos2");
+                return;
+            }
+        }
+
+        RegionManager regionManager = getRegionManager(p.getWorld());
+
+        //Region Bounds - Expands Vertically to Build limits. (make configurable?)
+        BlockVector3 corner1 = BlockVector3.at(
+                sel.getPos1().getBlockX(),
+                p.getWorld().getMaxHeight(),
+                sel.getPos1().getBlockZ()
+        );
+        BlockVector3 corner2 = BlockVector3.at(
+                sel.getPos2().getBlockX(),
+                p.getWorld().getMinHeight(),
+                sel.getPos2().getBlockZ()
+        );
+
+        //creates Plot
+        ProtectedRegion newRegion = new ProtectedCuboidRegion(p.getName() + "'s_Plot", corner1, corner2);
+
+        //convert Regions Map to List of ProtectedRegions
+        List<ProtectedRegion> otherRegions = new ArrayList<>(regionManager.getRegions().values());
+
+        //Checks for any intersecting regions
+        List<String> overlappingRegions = new LinkedList<>();
+        newRegion.getIntersectingRegions(otherRegions).forEach(i -> {
+            overlappingRegions.add(i.getId());
+        });
+
+        if(overlappingRegions.size() > 0){
+            p.sendMessage("§cYour Plot is overlapping with " + overlappingRegions);
+            return;
+        }
+
+        if(getRegionSize(newRegion) > MAX_PLOT_SIZE){
+            p.sendMessage("§cYour Plot cannot exeed " + MAX_PLOT_SIZE + " Blocks in Size");
+            return;
+        }
+
+
+        //adds Player to its newly created Plot as owner
+        DefaultDomain plotOwner = newRegion.getOwners();
+        plotOwner.addPlayer(p.getUniqueId());
+        newRegion.setOwners(plotOwner);
+
+        regionManager.addRegion(newRegion);
+
+        p.sendMessage("§aYour Plot from " + corner1 + " to " + corner2 + " is now protected!");
+
+    }
+
+    private void unclaimPLot(Player p){
+
+        ProtectedRegion regionFromOwner = getRegionFromOwner(p, p.getLocation());
+
+        if(regionFromOwner != null){
+            getRegionManager(p.getWorld()).removeRegion(regionFromOwner.getId());
+            p.sendMessage("§aSuccessfully removed " + regionFromOwner.getId());
+            return;
+        }
+
+        p.sendMessage("§cCouldn't find a Plot that belongs to you here");
+    }
+
+    private void addMember(Player owner, Player newMember){
+
+        ProtectedRegion regionFromOwner = getRegionFromOwner(owner, owner.getLocation());
+
+        if(regionFromOwner != null){
+            regionFromOwner.getMembers().addPlayer(newMember.getUniqueId());
+            owner.sendMessage("§aAdded " + newMember.getName() + " to " + regionFromOwner.getId());
+            return;
+        }
+
+        owner.sendMessage("§cYou have to be standing in your Plot as Owner");
+    }
+
+    private void removeMember(Player owner, Player oldMember){
+
+        ProtectedRegion regionFromOwner = getRegionFromOwner(owner, owner.getLocation());
+
+        if(regionFromOwner != null){
+
+            if(regionFromOwner.getMembers().contains(oldMember.getUniqueId())){
+
+                regionFromOwner.getMembers().removePlayer(oldMember.getUniqueId());
+                owner.sendMessage("§aSuccessfully removed Member " + oldMember.getName() + " from " + regionFromOwner.getId());
+                return;
+            }else{
+                owner.sendMessage("§c" + oldMember.getName() + " isn't Member of your PLot");
+            }
+
+            return;
+        }
+
+        owner.sendMessage("§cYou have to be standing in your Plot as Owner");
+    }
+
+    private void info(Player p, World w, Location location){
+
+        ApplicableRegionSet regionAt = getRegionAt(w, location);
+        for (ProtectedRegion region : regionAt) {
+            p.sendMessage("§aYou are in " + region.getId() + ". It goes from " + region.getMinimumPoint() + " to " + region.getMaximumPoint());
+            return;
+        }
+
+        p.sendMessage("§cThere is currently no Plot at your Location");
+    }
+
+    //get all regions the player is Standing in
+    private ApplicableRegionSet getRegionAt(World w, Location location){
+
+
+        BlockVector3 playerPos = BlockVector3.at(
+                location.getX(),
+                location.getY(),
+                location.getZ()
+        );
+
+        RegionManager regionManager = getRegionManager(w);
+        ApplicableRegionSet applicableRegions = regionManager.getApplicableRegions(playerPos);
+
+        return applicableRegions;
+    }
+
+    //returns the Region the player is standing in, if he is the owner. Otherwise null
+    private ProtectedRegion getRegionFromOwner(Player owner, Location location){
+        ApplicableRegionSet region = getRegionAt(owner.getWorld(), location);
+
+        for (ProtectedRegion protectedRegion : region) {
+            if (protectedRegion.getOwners().contains(owner.getUniqueId())) {
+                return protectedRegion;
+            }
+        }
+
+        return null;
+    }
+
+    private int chosenCommand(String arg){
+
+        for (int i = 0; i < cmds.length; i++) {
+            if(arg.equalsIgnoreCase(cmds[i]))return i + 1;
+        }
+
+        return -1;
+    }
+
+    private RegionManager getRegionManager(World w){
+        RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer();
+        return regionContainer.get(BukkitAdapter.adapt(w));
+    }
+
+    private int getRegionSize(ProtectedRegion region){
+        BlockVector3 maximumPoint = region.getMaximumPoint();
+        BlockVector3 minimumPoint = region.getMinimumPoint();
+
+        // Calculate the width and height of the rectangle
+        int width = Math.abs(minimumPoint.getBlockX() - maximumPoint.getBlockX()) + 1;
+        int height = Math.abs(minimumPoint.getBlockZ() - maximumPoint.getBlockZ()) + 1;
+
+        // Calculate the area of the rectangle
+        int area = width * height;
+
+        return area;
+    }
+
+    public static ArrayList<PlayerSelection> getSelectionsQeue(){
+        return selectionsQeue;
+    }
+    public static String[] getCmds(){
+        return cmds;
+    }
+
+}
diff --git a/src/main/java/Plots/PlotsTabComplete.java b/src/main/java/Plots/PlotsTabComplete.java
new file mode 100644
index 0000000..559a323
--- /dev/null
+++ b/src/main/java/Plots/PlotsTabComplete.java
@@ -0,0 +1,52 @@
+package Plots;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class PlotsTabComplete implements TabCompleter {
+
+    @Nullable
+    @Override
+    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+
+        if(!(sender instanceof Player)){
+            return null;
+        }
+
+        String[] cmds = Plots.getCmds();
+
+        Player p = (Player)sender;
+        List<String> tabCompletePhrases = new LinkedList<>();
+
+        switch (args.length){
+            case 0:
+                break;
+            case 1:
+                return Arrays.stream(cmds).toList();
+            case 2:
+
+                //players should be only listed when trying to add or remove member
+                if(!(args[1].equalsIgnoreCase(cmds[5]) || args[1].equalsIgnoreCase(cmds[6])))break;
+
+                //adds all players to tab complete
+                Bukkit.getServer().getOnlinePlayers().forEach(player -> {
+                    tabCompletePhrases.add(player.getName());
+                });
+
+                break;
+            default:
+        }
+
+        return tabCompletePhrases;
+    }
+}
diff --git a/src/main/java/fsi/pixelcampusessentials/PixelcampusEssentials.java b/src/main/java/fsi/pixelcampusessentials/PixelcampusEssentials.java
new file mode 100644
index 0000000..c5fc369
--- /dev/null
+++ b/src/main/java/fsi/pixelcampusessentials/PixelcampusEssentials.java
@@ -0,0 +1,36 @@
+package fsi.pixelcampusessentials;
+
+import Plots.PlayerSelection;
+import Plots.Plots;
+import Plots.PlotsTabComplete;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public final class PixelcampusEssentials extends JavaPlugin {
+
+    static private PixelcampusEssentials thisPlugin;
+    @Override
+    public void onEnable() {
+
+        thisPlugin = this;
+        saveDefaultConfig();
+        getConfig();
+
+        getServer().getPluginManager().registerEvents(new PlayerSelection(),this);
+
+        try {
+            getCommand("plot").setExecutor(new Plots());
+            getCommand("plot").setTabCompleter(new PlotsTabComplete());
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void onDisable() {
+        // Plugin shutdown logic
+    }
+
+    public static PixelcampusEssentials getPlugin(){
+        return thisPlugin;
+    }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..4285431
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,2 @@
+maxPlotSize:
+  - 62500
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..794c507
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,10 @@
+name: PixelcampusEssentials
+version: '${project.version}'
+main: fsi.pixelcampusessentials.PixelcampusEssentials
+api-version: 1.20
+depend: [WorldGuard]
+commands:
+  plot:
+    usage: '§c/plot [pos1,pos2,claim,unclaim,addmember,removemember,info]'
+    permission: pixelcampusEssentials.plot
+    permission-message: '§cYou dont have Permissions to use Plots'
\ No newline at end of file
-- 
GitLab