Initial commit

This commit is contained in:
Kristian Knarvik 2022-01-08 16:57:12 +01:00
commit d210b45ad5
11 changed files with 631 additions and 0 deletions

113
.gitignore vendored Normal file
View File

@ -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/

76
pom.xml Normal file
View File

@ -0,0 +1,76 @@
<?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>net.knarcraft</groupId>
<artifactId>permissionsigns</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>PermissionSigns</name>
<description>A plugin for selling permissions using signs</description>
<properties>
<java.version>16</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<url>git.knarcraft.net</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</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>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.17.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,83 @@
package net.knarcraft.permissionsigns;
import net.knarcraft.permissionsigns.container.SignCreationRequest;
import net.knarcraft.permissionsigns.thread.SignCreationRequestTimeoutThread;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.UUID;
import java.util.stream.Stream;
public final class PermissionSigns extends JavaPlugin {
private static Queue<SignCreationRequest> signCreationRequests = new PriorityQueue<>();
/**
* Gets the sign creation request for the player with the given UUID
*
* @param uuid <p>The UUID to get a sign creation request for</p>
* @return <p>A sign creation request, or null if the UUID is not found</p>
*/
public static SignCreationRequest getSignCreationRequest(UUID uuid) {
Stream<SignCreationRequest> matchingRequests = signCreationRequests.stream().filter(
(item) -> item.getPlayer().getUniqueId().equals(uuid));
List<SignCreationRequest> requestList = matchingRequests.toList();
if (!requestList.isEmpty()) {
return requestList.get(0);
} else {
return null;
}
}
@Override
public void onEnable() {
// Plugin startup logic
//TODO: Add commands create, add and remove
// /ps create, /ps add, and /ps remove
// create initiates the creation, and add adds properties
// On creation, write "Creating PermissionSign", first asked for the name
// Then asked for the permission. Allow several comma-separated permissions
// Then asked for duration
// Then asked for cost
// Say "Sign completed! Right-click a sign to enable it."
// Then asked to right-click a sign to create the new permission-sign
// Perhaps ignore the old ways, and just have one command for creating permission signs:
// /ps create <name> <permission> <duration> <cost> to create a new permission-sign
// Right-click a sign to create it
// /ps cancel to cancel the sing creation
// Break the sign to remove it, check for permission first
// The name thing is probably useless, as the sign's location works as its id
//TODO: Display and register the permission-sign
// Start with [PermSign] in red
// Next line is the permission node. Last child, upper-cased
// Third line is n seconds
// Last line is the cost, including the unit
// Need to store any temporary permissions in a list/queue and have a thread which searches for expired
// permissions to de-register them
//Not persistent, but might work as things shouldn't persist anyway
//player.addAttachment(this, "essentials.fly", true, seconds * 20);
//Vault probably has some API to add permissions
//TODO: Start sign creation when the create command is used and save the data until an empty sign is right-clicked
//TODO: Check for existence of old permission signs when clicked and register them as new permission signs. If
// it has the permissionSigns header and a name matching contents in signdata.yml, add it.
BukkitScheduler scheduler = Bukkit.getScheduler();
scheduler.runTaskTimer(this, new SignCreationRequestTimeoutThread(signCreationRequests), 0L, 100L);
}
@Override
public void onDisable() {
// Plugin shutdown logic
}
}

View File

@ -0,0 +1,14 @@
package net.knarcraft.permissionsigns.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class CancelCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
return false;
}
}

View File

@ -0,0 +1,17 @@
package net.knarcraft.permissionsigns.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class CreateCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// /ps create <name> <permission,permission> <cost> <duration> to create a new permission-sign
//Name and permission(s) required, but duration and cost optional
return false;
}
}

View File

@ -0,0 +1,16 @@
package net.knarcraft.permissionsigns.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.List;
public class CreateTabCompleter implements TabCompleter {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
return null;
}
}

View File

@ -0,0 +1,124 @@
package net.knarcraft.permissionsigns.container;
import net.knarcraft.permissionsigns.PermissionSigns;
import org.bukkit.Location;
import java.util.ArrayList;
import java.util.List;
/**
* This class represents a placed and active permission sign
*/
public class PermissionSign {
private Location signLocation;
private String name;
private final List<String> permissionNodes;
private final int duration;
private final int cost;
/**
* Instantiates a new permission sign
*
* @param signLocation <p>The location of the permission sing in the world</p>
* @param name <p>The name to display on the permission sign</p>
* @param permissionNodes <p>The permissions granted when this permission sign is used</p>
* @param duration <p>The duration, in seconds, until the permission should be revoked. 0 for non-temporary</p>
* @param cost <p>The cost of using this permission sign</p>
*/
public PermissionSign(Location signLocation, String name, List<String> permissionNodes, int duration, int cost) {
this.signLocation = signLocation;
this.name = name;
this.permissionNodes = new ArrayList<>(permissionNodes);
this.duration = Math.max(0, duration);
this.cost = Math.max(0, cost);
}
/**
* Instantiates a new permission sign
*
* @param permissionNodes <p>The permissions granted when this permission sign is used</p>
* @param duration <p>The duration, in seconds, until the permission should be revoked. 0 for non-temporary</p>
* @param cost <p>The cost of using this permission sign</p>
*/
public PermissionSign(List<String> permissionNodes, int duration, int cost) {
this.permissionNodes = new ArrayList<>(permissionNodes);
this.duration = Math.max(0, duration);
this.cost = Math.max(0, cost);
}
/**
* Sets the sign location of this permission sign
*
* @param signLocation <p>>The location of this permission sign's actual sign</p>
*/
public void setSignLocation(Location signLocation) {
if (this.signLocation == null) {
this.signLocation = signLocation;
} else {
throw new IllegalArgumentException("A sign location cannot be overwritten");
}
}
/**
* Gets the location of this permission sign
*
* <p>The location might be null until a sign has been right-clicked</p>
*
* @return <p>The location of this permission sign</p>
*/
public Location getSignLocation() {
return signLocation;
}
/**
* Gets the name of this permission sign
*
* @return <p>The name of this permission sign</p>
*/
public String getName() {
return name;
}
/**
* Gets the permissions nodes granted by this permission sign
*
* @return <p>The permission nodes granted by this permission sign</p>
*/
public List<String> getPermissionNodes() {
return new ArrayList<>(this.permissionNodes);
}
/**
* Gets the duration the permissions should last before expiring
*
* <p>A duration of 0 will give a permanent permission.</p>
*
* @return <p>The duration of the permissions</p>
*/
public int getDuration() {
return this.duration;
}
/**
* Gets the cost of using this permissions sign
*
* @return <p>The cost of using this permission sign</p>
*/
public int getCost() {
return this.cost;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof PermissionSign)) {
return false;
}
if (this == other) {
return true;
}
return this.signLocation.equals(((PermissionSign) other).signLocation);
}
}

View File

@ -0,0 +1,70 @@
package net.knarcraft.permissionsigns.container;
import org.bukkit.entity.Player;
/**
* A sign creation request represents the state where a player has used the create command, but not clicked a sign
*/
public class SignCreationRequest implements Comparable<SignCreationRequest> {
private final PermissionSign permissionSign;
private final Player player;
private final long initiationTime;
/**
* Instantiates a new sign creation request
*
* @param permissionSign <p>The sign which is about to be created</p>
* @param player <p>The player starting to create the permission sign</p>
* @param initiationTime <p></p>
*/
public SignCreationRequest(PermissionSign permissionSign, Player player, long initiationTime) {
this.permissionSign = permissionSign;
this.player = player;
this.initiationTime = initiationTime;
}
/**
* Gets the permission sign involved in this request
*
* @return <p>The involved permission sign</p>
*/
public PermissionSign getPermissionSign() {
return this.permissionSign;
}
/**
* Gets the player involved in this request
*
* @return <p>The involved player</p>
*/
public Player getPlayer() {
return this.player;
}
/**
* Gets the time this sign creation request was initiated
*
* @return <p>The time this request was initiated</p>
*/
public long initiationTime() {
return this.initiationTime;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof SignCreationRequest otherRequest)) {
return false;
}
if (this == other) {
return true;
}
return this.getPlayer().getUniqueId() == otherRequest.getPlayer().getUniqueId();
}
@Override
public int compareTo(SignCreationRequest other) {
return (int) (this.initiationTime - other.initiationTime);
}
}

View File

@ -0,0 +1,65 @@
package net.knarcraft.permissionsigns.listener;
import net.knarcraft.permissionsigns.PermissionSigns;
import net.knarcraft.permissionsigns.container.SignCreationRequest;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import java.util.Arrays;
public class SignListener implements Listener {
/**
* This event handler detects if a player clicks a button or a sign
*
* @param event <p>The player interact event which was triggered</p>
*/
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
Block block = event.getClickedBlock();
if (block == null) {
return;
}
Material material = block.getBlockData().getMaterial();
if (!Tag.SIGNS.isTagged(material) && !Tag.WALL_SIGNS.isTagged(material)) {
return;
}
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
Sign sign = (Sign) block.getState();
handleSignRightClick(sign, player);
}
}
/**
* Handles the right-clicking action
*
* @param sign <p>The clicked sign</p>
* @param player <p>The player that clicked the sign</p>
*/
private void handleSignRightClick(Sign sign, Player player) {
String[] lines = sign.getLines();
//Don't allow non-empty signs to be overwritten
if (!Arrays.stream(lines).allMatch(String::isEmpty)) {
return;
}
SignCreationRequest request = PermissionSigns.getSignCreationRequest(player.getUniqueId());
if (request == null) {
return;
}
//TODO: Register the sign and remove the request
}
}

View File

@ -0,0 +1,36 @@
package net.knarcraft.permissionsigns.thread;
import net.knarcraft.permissionsigns.container.SignCreationRequest;
import java.util.Queue;
/**
* The sign creation request timeout thread is responsible for removing sign creation requests as they time out
*/
public class SignCreationRequestTimeoutThread implements Runnable {
private final Queue<SignCreationRequest> signCreationRequests;
/**
* Instantiates a new sign creation request timeout thread
*
* @param signCreationRequests <p>A pointer to the queue of sign creation requests</p>
*/
public SignCreationRequestTimeoutThread(Queue<SignCreationRequest> signCreationRequests) {
this.signCreationRequests = signCreationRequests;
}
@Override
public void run() {
long currentTime = System.currentTimeMillis();
int requestTimeoutSeconds = 20;
SignCreationRequest firstElement = signCreationRequests.peek();
while (firstElement != null && currentTime > firstElement.initiationTime() + (1000 * requestTimeoutSeconds)) {
//Remove any expired sign creation requests
signCreationRequests.remove();
firstElement = signCreationRequests.peek();
}
}
}

View File

@ -0,0 +1,17 @@
name: PermissionSigns
version: '${project.version}'
main: net.knarcraft.permissionsigns.Permissionsigns
api-version: 1.17
prefix: PermissionSigns
depend: [ Vault ]
authors: [ EpicKnarvik97 ]
description: A plugin for selling permissions using signs
website: git.knarcraft.net
permissions:
permissionsigns.use:
description: Allows players to use the permission signs
default: true
permissionsigns.admin:
description: Allows players to create/destroy permissionsigns
default: op