3
0
Fork 0

First commit!

This commit is contained in:
stijnb1234 2020-04-18 09:01:35 +02:00
commit b487444b65
24 changed files with 4165 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.idea
*.iml

145
pom.xml Normal file
View file

@ -0,0 +1,145 @@
<?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>nl.SBDeveloper</groupId>
<artifactId>ThemeParkPlus</artifactId>
<version>2.0</version>
<packaging>jar</packaging>
<name>ThemeParkPlus</name>
<description>Plus version of ThemePark!</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<url>https://sbdplugins.nl</url>
<build>
<defaultGoal>clean package</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</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.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>de.tr7zw.changeme.nbtapi</pattern>
<shadedPattern>nl.sbdeveloper.themeparkplus.nbtapi</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>iobyte-repo</id>
<url>https://nexus.iobyte.nl/repository/maven-public/</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>CodeMC</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
<repository>
<id>sk89q-repo</id>
<url>>http://maven.sk89q.com/repo/</url>
</repository>
<repository>
<name>jcenter</name>
<id>bintray-jcenter</id>
<url>https://jcenter.bintray.com</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>nl.SBDevelopment</groupId>
<artifactId>SBUtilities</artifactId>
<version>1.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>me.paradoxpixel</groupId>
<artifactId>themepark</artifactId>
<version>1.3.2</version>
<scope>system</scope>
<systemPath>${pom.basedir}/src/lib/themepark-1.3.2.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>6.1.4-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>club.minnced</groupId>
<artifactId>discord-webhooks</artifactId>
<version>0.3.0</version>
</dependency>
</dependencies>
</project>

BIN
src/lib/themepark-1.3.2.jar Normal file

Binary file not shown.

View file

@ -0,0 +1,232 @@
package nl.sbdeveloper.themeparkplus;
import club.minnced.discord.webhook.WebhookClient;
import club.minnced.discord.webhook.WebhookClientBuilder;
import net.milkbowl.vault.economy.Economy;
import nl.SBDevelopment.SBUtilities.Data.YamlFile;
import nl.SBDevelopment.SBUtilities.Logger.Logger;
import nl.SBDevelopment.SBUtilities.PrivateManagers.UpdateManager;
import nl.SBDevelopment.SBUtilities.SBUtilities;
import nl.sbdeveloper.themeparkplus.commands.TPPCMD;
import nl.sbdeveloper.themeparkplus.listeners.AntiFreerunListener;
import nl.sbdeveloper.themeparkplus.listeners.DirectionalGateListener;
import nl.sbdeveloper.themeparkplus.listeners.FastpassListeners;
import nl.sbdeveloper.themeparkplus.listeners.StatusChangeListener;
import nl.sbdeveloper.themeparkplus.managers.DBManager;
import nl.sbdeveloper.themeparkplus.util.LGUtil;
import nl.sbdeveloper.themeparkplus.util.License;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Objects;
public final class ThemeParkPlus extends JavaPlugin {
private static ThemeParkPlus instance;
private static YamlFile config;
private static DBManager data;
private static YamlFile messages;
private static Economy econ = null;
private static WebhookClient webhookClient;
private int configVersion = 1;
@Override
public void onEnable() {
instance = this;
new SBUtilities(this, "ThemeParkPlus");
Logger.logInfo("-------------------------------", true);
Logger.logInfo("ThemeParkPlus v" + this.getDescription().getVersion(), true);
Logger.logInfo("Made by SBDeveloper", true);
Logger.logInfo(" ", true);
Logger.logInfo("Loading Files...", true);
config = new YamlFile("config");
config.loadDefaults();
data = new DBManager("data");
messages = new YamlFile("messages");
messages.loadDefaults();
Reader defConfigStream = new InputStreamReader(Objects.requireNonNull(getResource("config.yml")), StandardCharsets.UTF_8);
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream);
config.getFile().setDefaults(defConfig);
config.getFile().options().copyDefaults(true);
config.saveFile();
if (!config.getFile().contains("Version") || Objects.equals(config.getFile().getString("Version"), "")) {
config.getFile().set("Version", configVersion);
config.saveFile();
}
if (!Objects.equals(config.getFile().getString("Version"), String.valueOf(configVersion))) {
Logger.logInfo("Updating outdated config...", true);
updateConfig();
}
Logger.logInfo("Checking license...", true);
if (config.getFile().contains("License")) {
Logger.logInfo("Licence code: " + config.getFile().getString("License"), true);
} else {
Logger.logError("Licence code unknown! Please change the config.yml!", true);
return;
}
new License(this, "TP", config.getFile().getString("License"));
new UpdateManager(this, 6, UpdateManager.CheckType.SBDPLUGINS).handleResponse((versionResponse, version) -> {
if (versionResponse == UpdateManager.VersionResponse.FOUND_NEW) {
Logger.logWarning("There is a new version available! Curent: " + this.getDescription().getVersion() + " New: " + version, true);
} else if (versionResponse == UpdateManager.VersionResponse.LATEST) {
Logger.logInfo("You are running the latest version [" + this.getDescription().getVersion() + "]!", true);
} else if (versionResponse == UpdateManager.VersionResponse.UNAVAILABLE) {
Logger.logError("Unable to perform an update check.", true);
}
}).check();
if (Bukkit.getPluginManager().getPlugin("ThemePark") == null) {
Logger.logError("Missing ThemePark! Please install it first.", true);
getServer().getPluginManager().disablePlugin(this);
return;
}
if (Bukkit.getPluginManager().getPlugin("WorldEdit") == null) {
Logger.logError("Missing WorldEdit! Please install it first.", true);
getServer().getPluginManager().disablePlugin(this);
return;
}
if (!setupEconomy()) {
Logger.logError("Missing Vault! Please install it first.", true);
getServer().getPluginManager().disablePlugin(this);
return;
}
Logger.logInfo("Loading commands...", true);
Objects.requireNonNull(getCommand("themeparkplus"), "Couldn't read command from plugin.yml!").setExecutor(new TPPCMD());
Logger.logInfo("Loading listeners...", true);
Bukkit.getPluginManager().registerEvents(new DirectionalGateListener(), this);
Bukkit.getPluginManager().registerEvents(new FastpassListeners(), this);
if (getSConfig().getFile().getBoolean("AntiFreerun.Enabled")) {
Bukkit.getPluginManager().registerEvents(new AntiFreerunListener(), this);
}
if (getSConfig().getFile().getBoolean("DiscordWebhook.Enabled")) {
String URL = getSConfig().getFile().getString("DiscordWebhook.WebhookURL");
if (URL != null) {
Bukkit.getPluginManager().registerEvents(new StatusChangeListener(), this);
Logger.logInfo("Loading Discord webhook...", true);
WebhookClientBuilder builder = new WebhookClientBuilder(URL);
builder.setThreadFactory((job) -> {
Thread thread = new Thread(job);
thread.setName("Hello");
thread.setDaemon(true);
return thread;
});
builder.setWait(true);
webhookClient = builder.build();
} else {
Logger.logError("Couldn't load the webhook builder! The URL is null.", true);
}
}
Logger.logInfo("Loading Lamp & Gate utils...", true);
try {
new LGUtil();
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
Logger.logError("Couldn't find classes for Lamp & Gate util. The plugin won't work as intended.", true);
}
Logger.logInfo("Plugin enabled!", true);
Logger.logInfo("-------------------------------", true);
}
@Override
public void onDisable() {
if (getSConfig().getFile().getBoolean("DiscordWebhook.Enabled")) {
webhookClient.close();
}
Logger.logInfo("Plugin disabled!", true);
instance = null;
}
public static ThemeParkPlus getInstance() {
return instance;
}
public static YamlFile getSConfig() {
return config;
}
public static DBManager getData() {
return data;
}
public static YamlFile getMessages() {
return messages;
}
public static Economy getEconomy() {
return econ;
}
public static WebhookClient getWebhookClient() {
return webhookClient;
}
private boolean setupEconomy() {
if (getServer().getPluginManager().getPlugin("Vault") == null) {
return false;
}
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null) {
return false;
}
econ = rsp.getProvider();
return econ != null;
}
private void updateConfig() {
HashMap< String, Object > newConfig = getConfigVals();
for (String var: config.getFile().getKeys(false)) {
newConfig.remove(var);
}
if (newConfig.size() != 0) {
for (String key: newConfig.keySet()) {
config.getFile().set(key, newConfig.get(key));
}
config.getFile().set("Version", configVersion);
config.saveFile();
}
}
@NotNull
private HashMap<String, Object> getConfigVals() {
HashMap<String, Object> var = new HashMap <>();
Reader defConfigStream = new InputStreamReader(Objects.requireNonNull(getResource("config.yml")), StandardCharsets.UTF_8);
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream);
for (String key : defConfig.getKeys(false)) {
var.put(key, defConfig.get(key));
}
return var;
}
}

View file

@ -0,0 +1,31 @@
package nl.sbdeveloper.themeparkplus.api;
import nl.sbdeveloper.themeparkplus.api.objects.Gate;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
public class PlusAPI {
private static HashMap<Location, Gate> gates = new HashMap<>();
public static void addGate(Gate gate) {
gates.put(gate.getLoc(), gate);
}
public static void removeGate(@NotNull Gate gate) {
gates.remove(gate.getLoc());
}
public static boolean isGate(Location loc) {
return gates.containsKey(loc);
}
public static Gate getGate(Location loc) {
return gates.get(loc);
}
public static HashMap<Location, Gate> getGates() {
return gates;
}
}

View file

@ -0,0 +1,23 @@
package nl.sbdeveloper.themeparkplus.api.enums;
import org.bukkit.block.BlockFace;
public enum WalkingDirection {
/**
* The walking direction. Removed combinations because those can't be used in the commands.
*/
NORTH(BlockFace.NORTH),
EAST(BlockFace.EAST),
SOUTH(BlockFace.SOUTH),
WEST(BlockFace.WEST);
private BlockFace blockFace;
WalkingDirection(BlockFace blockFace) {
this.blockFace = blockFace;
}
public BlockFace getBlockFace() {
return blockFace;
}
}

View file

@ -0,0 +1,68 @@
package nl.sbdeveloper.themeparkplus.api.objects;
import lombok.Getter;
import lombok.Setter;
import nl.sbdeveloper.themeparkplus.api.enums.WalkingDirection;
import org.bukkit.Location;
@Getter @Setter
public class Gate {
private final Location loc;
/* If max count */
private boolean hasMaxCount = false;
private int passedCount = 0;
private int maxCount;
/* If directional */
private boolean isDirectional = false;
private WalkingDirection direction;
/**
* Constructor for a normal gate.
*
* @param loc The gate location
*/
public Gate(Location loc) {
this.loc = loc;
}
/**
* Constructor for a directional gate.
*
* @param loc The gate location
* @param direction The walking direction
*/
public Gate(Location loc, WalkingDirection direction) {
this.loc = loc;
this.isDirectional = true;
this.direction = direction;
}
/**
* Constructor for a max count gate.
*
* @param loc The gate location
* @param maxCount The max player count
*/
public Gate(Location loc, int maxCount) {
this.loc = loc;
this.hasMaxCount = true;
this.maxCount = maxCount;
}
/**
* Constructor for a directional max count gate.
*
* @param loc The gate location
* @param maxCount The max player count
* @param direction The walking direction
*/
public Gate(Location loc, int maxCount, WalkingDirection direction) {
this.loc = loc;
this.hasMaxCount = true;
this.isDirectional = true;
this.maxCount = maxCount;
this.direction = direction;
}
}

View file

@ -0,0 +1,22 @@
package nl.sbdeveloper.themeparkplus.api.objects;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.UUID;
@Getter @Setter
public class MalfunctionReport {
private String rideID;
private UUID reporterUUID;
private LocalDateTime reportDate;
private String reason;
public MalfunctionReport(String rideID, UUID reporterUUID, LocalDateTime reportDate, String reason) {
this.rideID = rideID;
this.reporterUUID = reporterUUID;
this.reportDate = reportDate;
this.reason = reason;
}
}

View file

@ -0,0 +1,33 @@
package nl.sbdeveloper.themeparkplus.api.objects;
import com.sk89q.worldedit.regions.AbstractRegion;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import java.util.ArrayList;
public class WaitingRow {
@Getter @Setter private String rideID;
@Getter @Setter private AbstractRegion region;
@Getter @Setter private int waitingPlayers = 0;
@Getter @Setter private int waitingTimeMinutes = 0;
private ArrayList<Location> signLocations = new ArrayList<>();
public WaitingRow(String rideID, AbstractRegion region) {
this.rideID = rideID;
this.region = region;
}
public ArrayList<Location> getSignLocations() {
return signLocations;
}
public void addSignLocation(Location loc) {
this.signLocations.add(loc);
}
public void removeSignLocation(Location loc) {
this.signLocations.remove(loc);
}
}

View file

@ -0,0 +1,340 @@
package nl.sbdeveloper.themeparkplus.commands;
import nl.sbdeveloper.themeparkplus.ThemeParkPlus;
import nl.sbdeveloper.themeparkplus.api.PlusAPI;
import nl.sbdeveloper.themeparkplus.api.enums.WalkingDirection;
import nl.sbdeveloper.themeparkplus.api.objects.Gate;
import nl.sbdeveloper.themeparkplus.util.Cuboid;
import nl.sbdeveloper.themeparkplus.util.LGUtil;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
public class TPPCMD implements CommandExecutor {
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) {
if (args.length == 0) {
return helpCommand(sender);
} else if (args[0].equalsIgnoreCase("info") && args.length == 1) {
return infoCommand(sender);
} else if (args[0].equalsIgnoreCase("opengate") && args.length == 5) {
if (!sender.hasPermission("tpp.opengate")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return openGate(sender, args, 0, null);
} else if (args[0].equalsIgnoreCase("opengate") && args.length == 6) {
if (!sender.hasPermission("tpp.opengate")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
try {
int amount = Integer.parseInt(args[5]);
return openGate(sender, args, amount, null);
} catch (NumberFormatException ex) {
try {
WalkingDirection dir = WalkingDirection.valueOf(args[5]);
return openGate(sender, args, 0, dir);
} catch (Exception ex2) {
sender.sendMessage(ChatColor.RED + "Unknown direction or amount.");
return true;
}
}
} else if (args[0].equalsIgnoreCase("opengate") && args.length == 7) {
if (!sender.hasPermission("tpp.opengate")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
int amount;
WalkingDirection dir;
try {
amount = Integer.parseInt(args[5]);
} catch (NumberFormatException ex) {
sender.sendMessage(ChatColor.RED + "Unknown amount.");
ex.printStackTrace();
return true;
}
try {
dir = WalkingDirection.valueOf(args[6]);
} catch (Exception ex2) {
sender.sendMessage(ChatColor.RED + "Unknown direction.");
return true;
}
return openGate(sender, args, amount, dir);
} else if (args[0].equalsIgnoreCase("closegate") && args.length == 5) {
if (!sender.hasPermission("tpp.closegate")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return closeGate(sender, args);
} else if (args[0].equalsIgnoreCase("lampon") && args.length == 5) {
if (!sender.hasPermission("tpp.lampon")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return lampTurnOnCommand(sender, args, 0);
} else if (args[0].equalsIgnoreCase("lampon") && args.length == 6) {
if (!sender.hasPermission("tpp.lampon")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
int amount;
try {
amount = Integer.parseInt(args[5]);
} catch (NumberFormatException ex) {
sender.sendMessage(ChatColor.RED + "Unknown amount.");
return true;
}
return lampTurnOnCommand(sender, args, amount);
} else if (args[0].equalsIgnoreCase("lampoff") && args.length == 5) {
if (!sender.hasPermission("tpp.lampoff")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return lampTurnOffCommand(sender, args);
} else if (args[0].equalsIgnoreCase("lampson") && args.length == 8) {
if (!sender.hasPermission("tpp.lampson")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return lampsTurnOnCommand(sender, args, 0);
} else if (args[0].equalsIgnoreCase("lampson") && args.length == 9) {
if (!sender.hasPermission("tpp.lampson")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
int amount;
try {
amount = Integer.parseInt(args[8]);
} catch (NumberFormatException ex) {
sender.sendMessage(ChatColor.RED + "Unknown amount.");
return true;
}
return lampsTurnOnCommand(sender, args, amount);
} else if (args[0].equalsIgnoreCase("lampsoff") && args.length == 8) {
if (!sender.hasPermission("tpp.lampsoff")) {
sender.sendMessage(ChatColor.RED + "You don't have permission to do this.");
return true;
}
return lampsTurnOffCommand(sender, args);
}
return helpCommand(sender);
}
private boolean infoCommand(@NotNull CommandSender sender) {
sender.sendMessage("§1==================================");
sender.sendMessage("§6ThemeParkPlus plugin made by §aSBDeveloper");
sender.sendMessage("§6Version: " + ThemeParkPlus.getInstance().getDescription().getVersion());
sender.sendMessage("§6Type /themeparkplus help for more information!");
sender.sendMessage("§1==================================");
return true;
}
private boolean helpCommand(@NotNull CommandSender sender) {
sender.sendMessage("§8ThemeParkPlus commands:");
sender.sendMessage("§6/themeparkplus info§f: Gives you information about the plugin.");
sender.sendMessage("§6/themeparkplus help§f: Gives you this help page.");
sender.sendMessage(" ");
sender.sendMessage("§6/themeparkplus opengate <World> <X> <Y> <Z> [Player Count/Direction] [Direction]§f: Open a gate!");
sender.sendMessage("§6/themeparkplus closegate <World> <X> <Y> <Z>§f: Close a gate!");
sender.sendMessage(" ");
sender.sendMessage("§6/themeparkplus lampon <World> <X> <Y> <Z> [Seconds on] §f: Turn a lamp on!");
sender.sendMessage("§6/themeparkplus lampoff <World> <X> <Y> <Z>§f: Turn a lamp off!");
sender.sendMessage("§6/themeparkplus lampson <World> <X1> <Y1> <Z1> <X2> <Y2> <Z2> [Seconds on]§f: Turn multiple lamps on.");
sender.sendMessage("§6/themeparkplus lampsoff <World> <X1> <Y1> <Z1> <X2> <Y2> <Z2>§f: Turn multiple lamps off.");
return true;
}
private boolean openGate(CommandSender sender, @NotNull String[] args, int amount, WalkingDirection dir) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
Location loc = new Location(bworld, bx, by, bz);
Gate gate = null;
if (amount != 0 && dir == null) {
//GEEN ONEWAY MET WEL AANTAL
gate = new Gate(loc, amount);
} else if (amount == 0 && dir != null) {
//ONE WAY ZONDER AANTAL
gate = new Gate(loc, dir);
} else if (amount != 0) {
//WEL ONE WAY MET WEL AANTAL
gate = new Gate(loc, amount, dir);
}
if (gate != null) {
PlusAPI.addGate(gate);
}
Block b = loc.getBlock();
if (LGUtil.isOpenable(b)) {
if (LGUtil.isOpen(b)) {
sender.sendMessage(ChatColor.RED + "That gate is already opened!");
return true;
}
if (gate != null && gate.isDirectional()) {
LGUtil.openGate(b, gate.getDirection().getBlockFace());
} else {
LGUtil.openGate(b);
}
} else {
sender.sendMessage(ChatColor.RED + "That block is not a gate.");
return true;
}
if (amount != 0) {
sender.sendMessage(ChatColor.GREEN + "Gate opened for " + amount + " players!");
} else {
sender.sendMessage(ChatColor.GREEN + "Gate opened!");
}
return true;
}
private boolean closeGate(CommandSender sender, @NotNull String[] args) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
Location loc = new Location(bworld, bx, by, bz);
Block b = loc.getBlock();
if (LGUtil.isOpenable(b)) {
Gate gate = PlusAPI.getGate(loc);
if (gate != null) {
PlusAPI.removeGate(gate);
}
if (!LGUtil.isOpen(b)) {
sender.sendMessage(ChatColor.RED + "That gate is already closed!");
return true;
}
LGUtil.closeGate(b);
} else {
sender.sendMessage(ChatColor.RED + "That block is not a gate.");
return true;
}
sender.sendMessage(ChatColor.GREEN + "Gate closed!");
return true;
}
private boolean lampTurnOnCommand(CommandSender sender, @NotNull String[] args, int secOn) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
Location loc = new Location(bworld, bx, by, bz);
Block block = loc.getBlock();
if (secOn == 0) {
if (!LGUtil.zetLampAan(block)) {
sender.sendMessage(ChatColor.RED + "Couldn't turn the lamp on. Maybe it's not a lamp, or it's already on.");
return true;
}
sender.sendMessage(ChatColor.GREEN + "Lamp turned on!");
} else {
if (!LGUtil.zetLampAan(block)) {
sender.sendMessage(ChatColor.RED + "Couldn't turn the lamp on. Maybe it's not a lamp, or it's already on.");
return true;
}
Bukkit.getScheduler().runTaskLater(ThemeParkPlus.getInstance(), () -> LGUtil.zetLampUit(block), secOn * 20);
sender.sendMessage(ChatColor.GREEN + "Lamp turned on for " + secOn + " second(s)!");
}
return true;
}
private boolean lampTurnOffCommand(CommandSender sender, @NotNull String[] args) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
Location loc = new Location(bworld, bx, by, bz);
if (!LGUtil.zetLampUit(loc.getBlock())) {
sender.sendMessage(ChatColor.RED + "Couldn't turn the lamp off. Maybe it's not a lamp, or it's already off.");
return true;
}
sender.sendMessage(ChatColor.GREEN + "Lamp turned off!");
return true;
}
private boolean lampsTurnOnCommand(CommandSender sender, @NotNull String[] args, int secOn) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
double bx2 = Double.parseDouble(args[5]);
double by2 = Double.parseDouble(args[6]);
double bz2 = Double.parseDouble(args[7]);
Location loc = new Location(bworld, bx, by, bz);
Location loc2 = new Location(bworld, bx2, by2, bz2);
Cuboid cub = new Cuboid(loc, loc2);
if (secOn == 0) {
Bukkit.getScheduler().runTaskAsynchronously(ThemeParkPlus.getInstance(), () -> cub.getBlocks().forEach(block -> {
if (block.getType().name().contains("REDSTONE_LAMP")) Bukkit.getScheduler().runTask(ThemeParkPlus.getInstance(), () -> LGUtil.zetLampAan(block));
}));
sender.sendMessage(ChatColor.GREEN + "Lamps in region turned on!");
} else {
Bukkit.getScheduler().runTaskAsynchronously(ThemeParkPlus.getInstance(), () -> cub.getBlocks().forEach(block -> {
if (block.getType().name().contains("REDSTONE_LAMP")) Bukkit.getScheduler().runTask(ThemeParkPlus.getInstance(), () -> LGUtil.zetLampAan(block));
}));
Bukkit.getScheduler().runTaskLaterAsynchronously(ThemeParkPlus.getInstance(), () -> cub.getBlocks().forEach(block -> {
if (block.getType().name().contains("REDSTONE_LAMP")) Bukkit.getScheduler().runTask(ThemeParkPlus.getInstance(), () -> LGUtil.zetLampUit(block));
}), secOn * 20);
sender.sendMessage(ChatColor.GREEN + "Lamps in region turned on for " + secOn + " seconds!");
}
return true;
}
private boolean lampsTurnOffCommand(@NotNull CommandSender sender, @NotNull String[] args) {
World bworld = Bukkit.getWorld(args[1]);
double bx = Double.parseDouble(args[2]);
double by = Double.parseDouble(args[3]);
double bz = Double.parseDouble(args[4]);
double bx2 = Double.parseDouble(args[5]);
double by2 = Double.parseDouble(args[6]);
double bz2 = Double.parseDouble(args[7]);
Location loc = new Location(bworld, bx, by, bz);
Location loc2 = new Location(bworld, bx2, by2, bz2);
Cuboid cub = new Cuboid(loc, loc2);
Bukkit.getScheduler().runTaskAsynchronously(ThemeParkPlus.getInstance(), () -> cub.getBlocks().forEach(block -> {
if (block.getType().name().contains("REDSTONE_LAMP")) Bukkit.getScheduler().runTask(ThemeParkPlus.getInstance(), () -> LGUtil.zetLampUit(block));
}));
sender.sendMessage(ChatColor.GREEN + "Lamps in region turned off!");
return true;
}
}

View file

@ -0,0 +1,18 @@
package nl.sbdeveloper.themeparkplus.listeners;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class AntiFreerunListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player p = e.getPlayer();
if (!p.hasPermission("tpp.bypassantifreerun")) {
p.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 1000000, -2, false, false));
}
}
}

View file

@ -0,0 +1,70 @@
package nl.sbdeveloper.themeparkplus.listeners;
import nl.sbdeveloper.themeparkplus.api.PlusAPI;
import nl.sbdeveloper.themeparkplus.api.enums.WalkingDirection;
import nl.sbdeveloper.themeparkplus.api.objects.Gate;
import nl.sbdeveloper.themeparkplus.util.DirectionUtil;
import nl.sbdeveloper.themeparkplus.util.LGUtil;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class DirectionalGateListener implements Listener {
@EventHandler
public void onWalkThroughFenceGate(PlayerMoveEvent e) {
if (e.getTo() != null
&& (e.getFrom().getBlockX() != e.getTo().getBlockX()
|| e.getFrom().getBlockY() != e.getTo().getBlockY()
|| e.getFrom().getBlockZ() != e.getTo().getBlockZ())) {
Location oldLoc = e.getFrom();
Location newLoc = e.getTo();
Block oldBlock = oldLoc.getBlock();
if (oldBlock.getType().name().contains("FENCE_GATE")) {
Gate gate = PlusAPI.getGate(oldBlock.getLocation());
if (gate == null) return;
if (!gate.isDirectional()) {
if (gate.getMaxCount() != 0) {
if (gate.getPassedCount() + 1 == gate.getMaxCount()) {
if (LGUtil.isOpenable(oldBlock)) {
LGUtil.closeGate(oldBlock);
} else {
PlusAPI.removeGate(gate);
return;
}
PlusAPI.removeGate(gate);
} else {
gate.setPassedCount(gate.getPassedCount() + 1);
}
}
} else {
WalkingDirection loopdir = DirectionUtil.getDirection(oldLoc.getBlockX(), oldLoc.getBlockZ(), newLoc.getBlockX(), newLoc.getBlockZ());
if (loopdir == null) return;
if (loopdir.getBlockFace() != gate.getDirection().getBlockFace()) {
e.getPlayer().teleport(oldLoc);
e.getPlayer().sendMessage(ChatColor.RED + "You can't walk in that direction.");
return;
}
if (gate.getMaxCount() != 0) {
if (gate.getPassedCount() + 1 == gate.getMaxCount()) {
if (LGUtil.isOpenable(oldBlock)) {
LGUtil.closeGate(oldBlock);
} else {
PlusAPI.removeGate(gate);
return;
}
PlusAPI.removeGate(gate);
} else {
gate.setPassedCount(gate.getPassedCount() + 1);
}
}
}
}
}
}
}

View file

@ -0,0 +1,149 @@
package nl.sbdeveloper.themeparkplus.listeners;
import de.tr7zw.changeme.nbtapi.NBTItem;
import me.paradoxpixel.themepark.api.API;
import me.paradoxpixel.themepark.api.attraction.Attraction;
import me.paradoxpixel.themepark.api.attraction.component.Status;
import nl.sbdeveloper.themeparkplus.ThemeParkPlus;
import nl.sbdeveloper.themeparkplus.util.ConfigUtil;
import nl.sbdeveloper.themeparkplus.util.LGUtil;
import nl.sbdeveloper.themeparkplus.util.XMaterial;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
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.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Collections;
public class FastpassListeners implements Listener {
@EventHandler
public void onCreate(SignChangeEvent e) {
Player p = e.getPlayer();
String[] lines = e.getLines();
if (!p.hasPermission("tpp.fastpass.create")) {
p.sendMessage(ChatColor.RED + "You don't have the permission to do this.");
return;
}
if (!API.isAttraction(e.getLine(2))) {
p.sendMessage(ChatColor.RED + e.getLine(2) + " is not an existing ride.");
return;
}
if (lines[0].equalsIgnoreCase("[ThemeParkPlus]") && lines[1].equalsIgnoreCase("Machine") && !lines[2].isEmpty() && !lines[3].isEmpty()) {
e.setLine(0, ChatColor.GRAY + "[" + ChatColor.GOLD + "ThemeParkPlus" + ChatColor.GRAY + "]");
e.setLine(1, ChatColor.BLUE + "Machine");
} else if (lines[0].equalsIgnoreCase("[ThemeParkPlus]") && lines[1].equalsIgnoreCase("Scanner") && !lines[2].isEmpty() && !lines[3].isEmpty()) {
e.setLine(0, ChatColor.GRAY + "[" + ChatColor.GOLD + "ThemeParkPlus" + ChatColor.GRAY + "]");
e.setLine(1, ChatColor.RED + "Scanner");
}
}
@EventHandler
public void onSignClick(PlayerInteractEvent e) {
if (e.getClickedBlock() == null || e.getAction() != Action.RIGHT_CLICK_BLOCK || !(e.getClickedBlock().getState() instanceof Sign) || e.getHand() != EquipmentSlot.HAND) return;
Sign sign = (Sign) e.getClickedBlock().getState();
if (ChatColor.stripColor(sign.getLine(1)).equalsIgnoreCase("Machine")) {
//Buy a ticket
String attID = sign.getLine(2);
if (!API.isAttraction(attID)) return;
Attraction att = API.getAttraction(attID);
double price;
try {
price = Double.parseDouble(sign.getLine(3));
} catch (NumberFormatException ex) {
return;
}
ItemStack ticket = XMaterial.PAPER.parseItem();
if (ticket == null) return;
ItemMeta meta = ticket.getItemMeta();
if (meta == null) return;
meta.setDisplayName(ChatColor.GOLD + "Fasspass Ticket");
meta.setLore(Collections.singletonList(ChatColor.GOLD + "For: " + ConfigUtil.makecolored(att.getName())));
ticket.setItemMeta(meta);
NBTItem item = new NBTItem(ticket);
item.setString("RideID", attID);
item.setDouble("Price", price);
ticket = item.getItem();
if (ThemeParkPlus.getEconomy().getBalance(e.getPlayer()) < price) {
e.getPlayer().sendMessage(ChatColor.RED + "You can't pay this fastpass ticket.");
return;
}
for (ItemStack content : e.getPlayer().getInventory().getContents()) {
if (content == null || content.getType() == null || content.getType() == Material.AIR) continue;
NBTItem nbtContent = new NBTItem(content);
if (content.getType() == XMaterial.PAPER.parseMaterial() && content.hasItemMeta() && nbtContent.hasKey("RideID") && nbtContent.getString("RideID").equalsIgnoreCase(attID)) {
e.getPlayer().sendMessage(ChatColor.RED + "You already have a ticket for this ride.");
return;
}
}
ThemeParkPlus.getEconomy().withdrawPlayer(e.getPlayer(), price);
e.getPlayer().getInventory().addItem(ticket);
e.getPlayer().updateInventory();
e.getPlayer().sendMessage(ChatColor.GREEN + "Bought a Fastpass ticket for " + ConfigUtil.makecolored(att.getName()) + ChatColor.GREEN + ". You paid €" + String.format("%.2f", price) + " for it!");
} else if (ChatColor.stripColor(sign.getLine(1)).equalsIgnoreCase("Scanner")) {
//Scan a ticket
if (!API.isAttraction(sign.getLine(2))) {
e.getPlayer().sendMessage(ChatColor.RED + "This sign is incorrect! The attraction doesn't exists.");
return;
}
Attraction att = API.getAttraction(sign.getLine(2));
ItemStack content = e.getPlayer().getInventory().getItemInMainHand();
NBTItem nbtContent = new NBTItem(content);
if (content.getType() == Material.AIR
|| !content.hasItemMeta() || !nbtContent.hasKey("RideID")) {
e.getPlayer().sendMessage(ChatColor.RED + "You need a fastpass ticket to go through the fastpass line.");
return;
}
if (att.getStatus() != Status.OPEN && att.getStatus() != Status.ACTIVE) {
e.getPlayer().sendMessage(ChatColor.RED + "This attraction is closed.");
return;
}
try {
String[] locationString = sign.getLine(3).split(":");
int x = Integer.parseInt(locationString[0]);
int y = Integer.parseInt(locationString[1]);
int z = Integer.parseInt(locationString[2]);
Block b = e.getPlayer().getWorld().getBlockAt(x, y, z);
if (LGUtil.isOpenable(b)) {
LGUtil.openGate(b);
Bukkit.getScheduler().scheduleSyncDelayedTask(ThemeParkPlus.getInstance(), () -> LGUtil.closeGate(b), 60L);
} else {
Location tpLoc = new Location(e.getPlayer().getWorld(), x, y, z, e.getPlayer().getLocation().getYaw(), e.getPlayer().getLocation().getPitch());
e.getPlayer().teleport(tpLoc);
}
e.getPlayer().getInventory().remove(e.getPlayer().getInventory().getItemInMainHand());
e.getPlayer().updateInventory();
e.getPlayer().sendMessage(ChatColor.GREEN + "Successfully redeemed your fastpass ticket!");
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ex) {
e.getPlayer().sendMessage(ChatColor.RED + "This sign is incorrect!");
}
}
}
}

View file

@ -0,0 +1,41 @@
package nl.sbdeveloper.themeparkplus.listeners;
import club.minnced.discord.webhook.send.WebhookEmbed;
import club.minnced.discord.webhook.send.WebhookEmbedBuilder;
import me.paradoxpixel.themepark.api.attraction.component.Status;
import me.paradoxpixel.themepark.api.event.attraction.StatusChangeEvent;
import me.paradoxpixel.themepark.attraction.status.StatusManager;
import nl.sbdeveloper.themeparkplus.ThemeParkPlus;
import nl.sbdeveloper.themeparkplus.util.ConfigUtil;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class StatusChangeListener implements Listener {
@EventHandler
public void onStatusChange(StatusChangeEvent e) {
if (e.getStatusAfter() != Status.GLOBAL) {
String title = ThemeParkPlus.getSConfig().getFile().getString("DiscordWebhook.Embed.Title");
if (title == null) return;
String rideName = ChatColor.stripColor(ConfigUtil.makecolored(e.getAttraction().getName()));
String statusAfter = ChatColor.stripColor(ConfigUtil.makecolored(StatusManager.getName(e.getStatusAfter())));
title = title.replaceAll("%RideName%", rideName);
String copy = ThemeParkPlus.getSConfig().getFile().getString("DiscordWebhook.Embed.Copyright");
String copyimg = ThemeParkPlus.getSConfig().getFile().getString("DiscordWebhook.Embed.CopyrightImage");
Integer color = ThemeParkPlus.getSConfig().getFile().getInt("DiscordWebhook.Embed.Colors." + e.getStatusAfter().toString());
if (copy == null || copyimg == null) return;
WebhookEmbed embed = new WebhookEmbedBuilder()
.setTitle(new WebhookEmbed.EmbedTitle(title, ""))
.setFooter(new WebhookEmbed.EmbedFooter(copy, copyimg))
.setColor(color)
.addField(new WebhookEmbed.EmbedField(false, rideName, statusAfter))
.build();
ThemeParkPlus.getWebhookClient().send(embed);
}
}
}

View file

@ -0,0 +1,81 @@
package nl.sbdeveloper.themeparkplus.managers;
import com.google.gson.Gson;
import nl.SBDevelopment.SBUtilities.Data.SQLiteDB;
import nl.SBDevelopment.SBUtilities.Utils.LocationSerializer;
import nl.sbdeveloper.themeparkplus.api.PlusAPI;
import nl.sbdeveloper.themeparkplus.api.objects.Gate;
import org.bukkit.Location;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
public class DBManager {
private static SQLiteDB data;
private static Connection con;
public DBManager(String name) {
data = new SQLiteDB(name);
try {
con = data.getConnection();
String query = "CREATE TABLE IF NOT EXISTS gates (gateLocation varchar(255) NOT NULL, gateData blob NOT NULL, UNIQUE (gateLocation))";
PreparedStatement statement = con.prepareStatement(query);
statement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void load() throws SQLException {
/* Load gates */
String query = "SELECT * FROM gates";
PreparedStatement statement = con.prepareStatement(query);
ResultSet gateSet = statement.executeQuery();
while (gateSet.next()) {
//Loading a gates...
byte[] blob = gateSet.getBytes("gateData");
String json = new String(blob);
Gson gson = new Gson();
Gate gate = gson.fromJson(json, Gate.class);
PlusAPI.addGate(gate);
}
}
public void save() {
for (Map.Entry<Location, Gate> entry : PlusAPI.getGates().entrySet()) {
Gson gson = new Gson();
byte[] blob = gson.toJson(entry.getValue()).getBytes();
try {
String query = "INSERT INTO gates (gateLocation, gateData) VALUES (?, ?)";
PreparedStatement statement = con.prepareStatement(query);
statement.setString(1, LocationSerializer.serialize(entry.getKey()));
statement.setBytes(2, blob);
statement.executeUpdate();
} catch (SQLException ignored) {}
try {
String query2 = "UPDATE gates SET gateData = ? WHERE gateLocation = ?";
PreparedStatement statement2 = con.prepareStatement(query2);
statement2.setBytes(1, blob);
statement2.setString(2, LocationSerializer.serialize(entry.getKey()));
statement2.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void closeConnection() {
data.closeSource();
}
}

View file

@ -0,0 +1,11 @@
package nl.sbdeveloper.themeparkplus.util;
import org.bukkit.ChatColor;
import org.jetbrains.annotations.NotNull;
public class ConfigUtil {
@NotNull
public static String makecolored(String str) {
return ChatColor.translateAlternateColorCodes('&', str);
}
}

View file

@ -0,0 +1,177 @@
package nl.sbdeveloper.themeparkplus.util;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class Cuboid implements Cloneable, ConfigurationSerializable, Iterable<Block> {
protected String worldName;
protected final Vector minimumPoint, maximumPoint;
public Cuboid(@NotNull Cuboid cuboid) {
this(cuboid.worldName, cuboid.minimumPoint.getX(), cuboid.minimumPoint.getY(), cuboid.minimumPoint.getZ(), cuboid.maximumPoint.getX(), cuboid.maximumPoint.getY(), cuboid.maximumPoint.getZ());
}
public Cuboid(Location loc) {
this(loc, loc);
}
public Cuboid(Location loc1, Location loc2) {
if (loc1 != null && loc2 != null) {
if (loc1.getWorld() != null && loc2.getWorld() != null) {
if (!loc1.getWorld().getUID().equals(loc2.getWorld().getUID()))
throw new IllegalStateException("The 2 locations of the cuboid must be in the same world!");
} else {
throw new NullPointerException("One/both of the worlds is/are null!");
}
this.worldName = loc1.getWorld().getName();
double xPos1 = Math.min(loc1.getX(), loc2.getX());
double yPos1 = Math.min(loc1.getY(), loc2.getY());
double zPos1 = Math.min(loc1.getZ(), loc2.getZ());
double xPos2 = Math.max(loc1.getX(), loc2.getX());
double yPos2 = Math.max(loc1.getY(), loc2.getY());
double zPos2 = Math.max(loc1.getZ(), loc2.getZ());
this.minimumPoint = new Vector(xPos1, yPos1, zPos1);
this.maximumPoint = new Vector(xPos2, yPos2, zPos2);
} else {
throw new NullPointerException("One/both of the locations is/are null!");
}
}
public Cuboid(String worldName, double x1, double y1, double z1, double x2, double y2, double z2) {
if (worldName == null || Bukkit.getServer().getWorld(worldName) == null)
throw new NullPointerException("One/both of the worlds is/are null!");
this.worldName = worldName;
double xPos1 = Math.min(x1, x2);
double xPos2 = Math.max(x1, x2);
double yPos1 = Math.min(y1, y2);
double yPos2 = Math.max(y1, y2);
double zPos1 = Math.min(z1, z2);
double zPos2 = Math.max(z1, z2);
this.minimumPoint = new Vector(xPos1, yPos1, zPos1);
this.maximumPoint = new Vector(xPos2, yPos2, zPos2);
}
public boolean containsLocation(Location location) {
return location != null && location.getWorld().getName().equals(this.worldName) && location.toVector().isInAABB(this.minimumPoint, this.maximumPoint);
}
public boolean containsVector(Vector vector) {
return vector != null && vector.isInAABB(this.minimumPoint, this.maximumPoint);
}
public List<Block> getBlocks() {
List<Block> blockList = new ArrayList<>();
World world = this.getWorld();
if (world != null) {
for (int x = this.minimumPoint.getBlockX(); x <= this.maximumPoint.getBlockX(); x++) {
for (int y = this.minimumPoint.getBlockY(); y <= this.maximumPoint.getBlockY() && y <= world.getMaxHeight(); y++) {
for (int z = this.minimumPoint.getBlockZ(); z <= this.maximumPoint.getBlockZ(); z++) {
blockList.add(world.getBlockAt(x, y, z));
}
}
}
}
return blockList;
}
public Location getLowerLocation() {
return this.minimumPoint.toLocation(this.getWorld());
}
public double getLowerX() {
return this.minimumPoint.getX();
}
public double getLowerY() {
return this.minimumPoint.getY();
}
public double getLowerZ() {
return this.minimumPoint.getZ();
}
public Location getUpperLocation() {
return this.maximumPoint.toLocation(this.getWorld());
}
public double getUpperX() {
return this.maximumPoint.getX();
}
public double getUpperY() {
return this.maximumPoint.getY();
}
public double getUpperZ() {
return this.maximumPoint.getZ();
}
public double getVolume() {
return (this.getUpperX() - this.getLowerX() + 1) * (this.getUpperY() - this.getLowerY() + 1) * (this.getUpperZ() - this.getLowerZ() + 1);
}
public World getWorld() {
World world = Bukkit.getServer().getWorld(this.worldName);
if (world == null) throw new NullPointerException("World '" + this.worldName + "' is not loaded.");
return world;
}
public void setWorld(World world) {
if (world != null) this.worldName = world.getName();
else throw new NullPointerException("The world cannot be null.");
}
@Override
public Cuboid clone() {
return new Cuboid(this);
}
@Override
public ListIterator<Block> iterator() {
return this.getBlocks().listIterator();
}
@Override
public Map<String, Object> serialize() {
Map<String, Object> serializedCuboid = new HashMap<>();
serializedCuboid.put("worldName", this.worldName);
serializedCuboid.put("x1", this.minimumPoint.getX());
serializedCuboid.put("x2", this.maximumPoint.getX());
serializedCuboid.put("y1", this.minimumPoint.getY());
serializedCuboid.put("y2", this.maximumPoint.getY());
serializedCuboid.put("z1", this.minimumPoint.getZ());
serializedCuboid.put("z2", this.maximumPoint.getZ());
return serializedCuboid;
}
@Nullable
public static Cuboid deserialize(Map<String, Object> serializedCuboid) {
try {
String worldName = (String) serializedCuboid.get("worldName");
double xPos1 = (Double) serializedCuboid.get("x1");
double xPos2 = (Double) serializedCuboid.get("x2");
double yPos1 = (Double) serializedCuboid.get("y1");
double yPos2 = (Double) serializedCuboid.get("y2");
double zPos1 = (Double) serializedCuboid.get("z1");
double zPos2 = (Double) serializedCuboid.get("z2");
return new Cuboid(worldName, xPos1, yPos1, zPos1, xPos2, yPos2, zPos2);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}

View file

@ -0,0 +1,39 @@
package nl.sbdeveloper.themeparkplus.util;
import nl.sbdeveloper.themeparkplus.api.enums.WalkingDirection;
import org.jetbrains.annotations.Nullable;
public class DirectionUtil {
@Nullable
public static WalkingDirection getDirection(int xoud, int zoud, int xnieuw, int znieuw) {
int changeInX = xnieuw - xoud;
int changeInZ = znieuw - zoud;
if (changeInZ != 0 && changeInX == 0) {
if (changeInZ < 0) {
return WalkingDirection.NORTH;
} else {
return WalkingDirection.SOUTH;
}
} else if (changeInX != 0 && changeInZ == 0) {
if (changeInX < 0) {
return WalkingDirection.WEST;
} else {
return WalkingDirection.EAST;
}
}
return null;
}
public static boolean isGoodDirection(WalkingDirection current, WalkingDirection good) {
if (current == WalkingDirection.EAST && good == WalkingDirection.EAST) {
return true;
} else if (current == WalkingDirection.NORTH && good == WalkingDirection.NORTH) {
return true;
} else if (current == WalkingDirection.SOUTH && good == WalkingDirection.SOUTH) {
return true;
} else return current == WalkingDirection.WEST && good == WalkingDirection.WEST;
}
}

View file

@ -0,0 +1,298 @@
package nl.sbdeveloper.themeparkplus.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import nl.sbdeveloper.themeparkplus.ThemeParkPlus;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.type.Gate;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
public class LGUtil {
private static List<Vector> offsets = new ArrayList<>();
private static List <Block> nearbyBlocks = new ArrayList<>();
private static boolean nieuweVersie = false;
private static Method getBlockDataMethod;
private static Method setBlockDataMethod;
private static Method getAsStringMethod;
private static Object lampAanData;
private static Object lampUitData;
public LGUtil() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
offsets.add(new Vector(1, 0, 0));
offsets.add(new Vector(-1, 0, 0));
offsets.add(new Vector(0, 1, 0));
offsets.add(new Vector(0, -1, 0));
offsets.add(new Vector(0, 0, 1));
offsets.add(new Vector(0, 0, -1));
Class<?> blockDataClass = Class.forName("org.bukkit.block.data.BlockData");
Method methodCreateBlockData = Bukkit.class.getMethod("createBlockData", String.class);
getBlockDataMethod = Block.class.getMethod("getBlockData");
setBlockDataMethod = Block.class.getMethod("setBlockData", blockDataClass,
Boolean.TYPE);
getAsStringMethod = blockDataClass.getMethod("getAsString");
lampAanData = methodCreateBlockData.invoke(null, "minecraft:redstone_lamp[lit=true]");
lampUitData = methodCreateBlockData.invoke(null, "minecraft:redstone_lamp[lit=false]");
nieuweVersie = true;
}
public static boolean zetLampAan(Block lampBlock) {
if (nieuweVersie) {
if (!isLamp(lampBlock)) {
Bukkit.getLogger().severe(lampBlock.getType().toString());
}
if (isAan(lampBlock)) {
Bukkit.getLogger().severe(getAsString(getBlockData(lampBlock)));
}
if ((isLamp(lampBlock)) && (!isAan(lampBlock))) {
setBlockData(lampBlock, lampAanData);
return true;
}
return false;
}
if (!isAan(lampBlock)) {
final Block neighbor = getNeighbor(lampBlock);
if (neighbor != null) {
BlockState neighborState = neighbor.getState();
try {
for (org.bukkit.util.Vector offset: offsets) {
Block neighborOfNeighbor = neighbor.getLocation().add(offset).getBlock();
if ((neighborOfNeighbor.getX() != lampBlock.getX()) || (neighborOfNeighbor.getY() != lampBlock.getY()) || (neighborOfNeighbor.getZ() != lampBlock.getZ())) {
nearbyBlocks.add(neighborOfNeighbor);
}
}
neighbor.setType(Material.REDSTONE_BLOCK);
} catch (Exception e) {
e.printStackTrace();
} finally {
neighborState.update(true, false);
Bukkit.getScheduler().runTaskLater(ThemeParkPlus.getInstance(), () -> {
for (Vector offset: offsets) {
Block neighborOfNeighbor = neighbor.getLocation().add(offset).getBlock();
nearbyBlocks.remove(neighborOfNeighbor);
}
}, 1L);
}
return true;
}
}
return false;
}
public static boolean zetLampUit(Block lampBlock) {
if (nieuweVersie) {
if ((isLamp(lampBlock)) && (isAan(lampBlock))) {
setBlockData(lampBlock, lampUitData);
return true;
}
return false;
}
if (isAan(lampBlock)) {
lampBlock.setType(Objects.requireNonNull(Material.matchMaterial(XMaterial.REDSTONE_LAMP.getLegacy()[0])));
return true;
}
return false;
}
public static boolean openGate(Block b) {
return openGate(b, getDirection(b));
}
public static boolean openGate(Block b, BlockFace openFace) {
if (nieuweVersie) {
org.bukkit.block.data.BlockData blockData = b.getBlockData();
if (isOpenable(b)) {
org.bukkit.block.data.Openable op = (org.bukkit.block.data.Openable) blockData;
if (op.isOpen()) return false;
op.setOpen(true);
b.setBlockData(blockData);
org.bukkit.block.data.Directional dir = (org.bukkit.block.data.Directional) blockData;
dir.setFacing(openFace);
b.setBlockData(blockData);
return true;
}
} else {
BlockState state = b.getState();
if (isOpenable(b)) {
org.bukkit.material.Openable openable = (org.bukkit.material.Openable) state.getData();
if (openable.isOpen()) return false;
openable.setOpen(true);
state.setData((org.bukkit.material.MaterialData) openable);
state.update();
org.bukkit.material.Directional dir = (org.bukkit.material.Directional) state.getData();
dir.setFacingDirection(openFace);
state.setData((org.bukkit.material.MaterialData) dir);
state.update();
return true;
}
}
return false;
}
public static boolean closeGate(Block b) {
if (nieuweVersie) {
org.bukkit.block.data.BlockData blockData = b.getBlockData();
if (isOpenable(b)) {
org.bukkit.block.data.Openable op = (org.bukkit.block.data.Openable) blockData;
if (!op.isOpen()) {
return false;
}
op.setOpen(false);
b.setBlockData(blockData);
return true;
}
} else {
BlockState state = b.getState();
if (isOpenable(b)) {
org.bukkit.material.Openable openable = (org.bukkit.material.Openable) state.getData();
if (!openable.isOpen()) {
return false;
}
openable.setOpen(false);
state.setData((org.bukkit.material.MaterialData) openable);
state.update();
return true;
}
}
return false;
}
@Nullable
public static BlockFace getDirection(Block b) {
if (nieuweVersie) {
org.bukkit.block.data.BlockData blockData = b.getBlockData();
if (isOpenable(b)) {
org.bukkit.block.data.Directional dir = (org.bukkit.block.data.Directional) blockData;
return dir.getFacing();
}
} else {
BlockState state = b.getState();
if (isOpenable(b)) {
org.bukkit.material.Directional dir = (org.bukkit.material.Directional) state.getData();
return dir.getFacing();
}
}
return null;
}
public static boolean isOpen(Block b) {
if (nieuweVersie) {
org.bukkit.block.data.BlockData blockData = b.getBlockData();
if (isOpenable(b)) {
org.bukkit.block.data.Openable op = (org.bukkit.block.data.Openable) blockData;
return op.isOpen();
}
} else {
BlockState state = b.getState();
if (isOpenable(b)) {
org.bukkit.material.Openable openable = (org.bukkit.material.Openable) state.getData();
return openable.isOpen();
}
}
return false;
}
/* Gate codes sponsored by MrWouter <3 */
public static boolean isOpenable(Block b) {
if (b == null) {
return false;
}
if (nieuweVersie) {
return b.getBlockData() instanceof org.bukkit.block.data.Openable;
} else {
return b.getState().getData() instanceof org.bukkit.material.Openable;
}
}
private static Block getNeighbor(Block lampBlock) {
List<Block> possibleNeighbors = new ArrayList<>();
if (lampBlock.getLocation().getY() > 0.0D) {
possibleNeighbors.add(lampBlock.getLocation().add(0.0D, -1.0D, 0.0D).getBlock());
}
if (lampBlock.getLocation().getY() < 255.0D) {
possibleNeighbors.add(lampBlock.getLocation().add(0.0D, 1.0D, 0.0D).getBlock());
}
possibleNeighbors.add(lampBlock.getLocation().add(0.0D, 0.0D, 1.0D).getBlock());
possibleNeighbors.add(lampBlock.getLocation().add(0.0D, 0.0D, -1.0D).getBlock());
possibleNeighbors.add(lampBlock.getLocation().add(1.0D, 0.0D, 0.0D).getBlock());
possibleNeighbors.add(lampBlock.getLocation().add(-1.0D, 0.0D, 0.0D).getBlock());
for (Block neighbor: possibleNeighbors) {
if (neighbor.getType() == Material.AIR) {
return neighbor;
}
}
for (Block neighbor: possibleNeighbors) {
if ((neighbor.getState().getClass().getSimpleName().equals("CraftBlockState")) && (neighbor.getType() != Material.valueOf(XMaterial.PISTON_HEAD.getLegacy()[0]) && neighbor.getType() != Material.valueOf(XMaterial.MOVING_PISTON.getLegacy()[1])) && (neighbor.getType() != Material.valueOf("REDSTONE_LAMP_ON"))) {
return neighbor;
}
}
for (Block neighbor: possibleNeighbors) {
if ((neighbor.getState().getClass().getSimpleName().equals("CraftBlockState")) && (neighbor.getType() != Material.valueOf(XMaterial.PISTON_HEAD.getLegacy()[0]) && neighbor.getType() != Material.valueOf(XMaterial.MOVING_PISTON.getLegacy()[1]))) {
return neighbor;
}
}
return null;
}
private static boolean isAan(Block lamp) {
return ((nieuweVersie) && (Objects.requireNonNull(getAsString(getBlockData(lamp))).contains("lit=true"))) || ((!nieuweVersie) && (lamp.getType() == Material.matchMaterial(XMaterial.REDSTONE_LAMP.getLegacy()[1])));
}
private static boolean isLamp(Block lamp) {
if (nieuweVersie) {
return lamp.getType() == XMaterial.REDSTONE_LAMP.parseMaterial();
} else {
return lamp.getType() == Material.matchMaterial(XMaterial.REDSTONE_LAMP.getLegacy()[1])
|| lamp.getType() == Material.matchMaterial(XMaterial.REDSTONE_LAMP.getLegacy()[0]);
}
}
private static void setBlockData(Block lamp, Object blockData) {
try {
setBlockDataMethod.invoke(lamp, blockData,
Boolean.FALSE);
} catch (Exception e) {
e.printStackTrace();
}
}
private static Object getBlockData(Block lamp) {
try {
return getBlockDataMethod.invoke(lamp);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String getAsString(Object blockData) {
try {
return (String) getAsStringMethod.invoke(blockData, new Object[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,264 @@
package nl.sbdeveloper.themeparkplus.util;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
/**
* License class for SBDevelopment
*
* v1.3 - Changed in 03-03-2020
*
* @author Stijn [SBDeveloper]
* @since 23-12-2019
*/
public class License {
/*
This file is part of ActionFoto.
Copyright (c) 2018-2020 SBDevelopment - All Rights Reserved
Unauthorized copying of this file, via any medium is strictly prohibited
Proprietary and confidential
Written by Stijn Bannink <stijnbannink23@gmail.com>, January 2020
*/
private Plugin plugin;
private String license;
private String prefix;
/**
* Construct a new license
* @param plugin The Main class [Javaplugin]
* @param prefix The prefix, like TPP or AF
* @param license The license from the config
*/
public License(Plugin plugin, String prefix, String license) {
this.prefix = prefix;
this.plugin = plugin;
this.license = license;
startTimer();
}
private void startTimer() {
Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, () -> {
if (!validateLicense()) {
Bukkit.getLogger().severe("[" + prefix + "] License is incorrect!");
}
}, 0, 20 * 60 * 60);
}
/**
* Check a license
*
* @return true/false
*/
private boolean validateLicense() {
String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/" + this.license;
@Nullable JsonObject res;
try {
res = sendGETRequestJSON(url);
} catch (IOException e) {
disable("GET_request_error");
return false;
}
if (res == null) {
disable("GET_request_error_2");
return false;
}
JsonObject dat = res.get("data").getAsJsonObject();
int stat = dat.get("status").getAsInt();
if (stat == 404) {
disable("status_404_error");
return false;
}
if (dat.get("licenseKey").isJsonNull()) {
disable("license_null_error");
return false;
}
if (!dat.get("licenseKey").getAsString().split("-")[0].contains(prefix)) {
disable("prefix_error");
return false;
}
switch(dat.get("status").getAsString()) {
case "2":
//activate?
break;
case "3":
//it's good
break;
default:
disable("status_error");
return false;
}
//Not activated? Activate it!
if (dat.get("timesActivated").isJsonNull() || dat.get("timesActivated").getAsString().equalsIgnoreCase("0")) {
return activate();
}
if (dat.get("expiresAt").isJsonNull()) {
disable("null_error");
return false;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
date = format.parse(dat.get("expiresAt").getAsString());
} catch (ParseException e) {
e.printStackTrace();
disable("null_error");
return false;
}
if (!(Objects.requireNonNull(date).after(new Date()))) {
disable("expired_error");
return false;
}
if (!dat.get("ipcheck").getAsBoolean()) {
disable("ip_error");
return false;
}
if (dat.get("port").isJsonNull()) {
disable("null_error");
return false;
}
try {
int por = dat.get("port").getAsInt();
if (por != Bukkit.getServer().getPort()) {
disable("port_error");
return false;
}
} catch(NumberFormatException e) {
disable("null_error");
return false;
}
return true;
}
/**
* Activate the license (private)
*
* @return true/false
*/
private boolean activate() {
String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/activate/" + this.license + "?port=" + Bukkit.getServer().getPort();
@Nullable JsonObject res;
try {
res = sendGETRequestJSON(url);
} catch (IOException e) {
e.printStackTrace();
disable("GET_request_error");
return false;
}
if (res == null) {
disable("GET_request_error_2");
return false;
}
JsonObject dat = res.get("data").getAsJsonObject();
int stat = dat.get("status").getAsInt();
if (stat == 404) {
disable("status_404_error");
return false;
}
if (dat.get("licenseKey").isJsonNull()) {
disable("license_null_error");
return false;
}
if (!dat.get("licenseKey").getAsString().split("-")[0].contains(prefix)) {
disable("prefix_error");
return false;
}
switch(dat.get("status").getAsString()) {
case "2":
//activate?
break;
case "3":
//it's good
break;
default:
disable("status_error");
return false;
}
//Still not activated? Something is wrong...
return !dat.get("timesActivated").isJsonNull() && !dat.get("timesActivated").getAsString().equalsIgnoreCase("0");
}
/**
* Disable the plugin (private)
*
* @param reason The disabling reason
*/
private void disable(String reason) {
Bukkit.getScheduler().runTask(plugin, () -> {
Bukkit.getLogger().severe("[" + plugin.getName() + "] " + "Stopping plugin because licensing system check failed.");
Bukkit.getLogger().severe("[" + plugin.getName() + "] " + "Reason: " + reason);
Bukkit.getPluginManager().disablePlugin(plugin);
});
}
/**
* Send an GET request with JSONObject response
*
* @param uri The URL
*
* @return The JSONObject
* @throws IOException URL errors
*/
@Nullable
private JsonObject sendGETRequestJSON(String uri) throws IOException {
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
String authStringEnc = "Y2tfMGEzNWEzMWE2NzExNmM3NDg2MGEwYTJhNjUxNGVjZjM4NTBmM2JmMDpjc185NmYxZGNlYjI4MWRkZDExOTBjMzQ3ZjJjYzMwMGNjZTIzYWNhODI1";
con.setRequestProperty("Authorization", "Basic " + authStringEnc);
int code = con.getResponseCode();
if (code == 404) {
disable("404_error");
return null;
}
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JsonParser parser = new JsonParser();
return parser.parse(response.toString()).getAsJsonObject();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
License: 'TP-ABC-ABC'
AntiFreerun:
Enabled: false
Fastpass:
ItemName: '&6ThemeParkTicket'
MachineSign:
Row1: "&3[ThemePark]"
Row2: "&bMachine"
ControlSign:
Row1: "&3[ThemePark]"
Row2: "&bControl"
DiscordWebhook:
Enabled: false
WebhookURL: ""
Embed:
Title: "%RideName% - Status change"
Copyright: "Copyright ThemePark 2020"
CopyrightImage: "https://www.spigotmc.org/data/resource_icons/48/48648.jpg?1544984106"
Colors:
OPEN: 0x55FF55
CLOSED: 0xAA0000
MAINTENANCE: 0xFFAA00
CONSTRUCTION: 0xAAAAAA
MALFUNCTION: 0xAA00AA
ACTIVE: 0x55FF55
INACTIVE: 0xAA0000
WaitingRows:
MinutesPerWaitingPerson: 2
Sign:
Row1: "&3[ThemePark]"
Row2: "&bWaitingrow"
Row3: "%AttractionName%"
Row4: "%WaitTime% min."

View file

@ -0,0 +1,45 @@
General:
OnlyForPlayers: "&cOnly players can run this command!"
NoPermission: "&cYou don't have the permission to do this!"
Gates:
Open:
ChooseDirection: "&cYou have to choose between: NORTH, EAST, SOUTH and WEST"
AlreadyOpen: "&cThat gate is already opened!"
Opened: "&aThat gate is now open!"
OpenedPlayers: "&aThat gate is now open! A maximum of %COUNT% %SINGMULTI:visitor:visitors% can now walk through it!"
Close:
AlreadyClosed: "&cThat gate is already closed!"
Closed: "&aThat gate is now closed!"
NoGate: "&cThat block is not a gate!"
NoGateConsole: "&cThe gate on the location %LocationXYZ% in the world %World% couldn't be find! It's now removed of the data!"
InvalidDirection: "&cYou can't walk through that gate in this direction!"
Lamps:
TurnOn:
NoLampOrAlreadyOn: "&cCouldn't turn that lamp on! Maybe it's already on, or it's not a redstone lamp."
IncorrectNumber: "&cThe number of seconds isn't correct! Give a number please."
TurnedOn: "&aThat lamp is succesfully turned on!"
TurnedOnSeconds: "&fThat lamp is succesfully turned on for %COUNT% %SINGMULTI:second:seconds%!"
TurnOff:
NoLampOrAlreadyOff: "&cCouldn't turn that lamp off! Maybe it's already off, or it's not a redstone lamp."
TurnedOff: "&aThat lamp is succesfully turned off!"
Fastpass:
NotEnoughMoney: "&cYou don't have enough money for this Fastpass ticket!"
AlreadyHasOne: "&cYou've already got a Fastpass ticket for this ride!"
MoneyWithdrawed: "&aA amount of $%MoneyAmount%,- is taken of your account!"
WrongLocation: "&cThat sign contains wrong coordinates!"
Expired: "&cYour fastpass ticket is already expired!"
NotOpen: "&cThat ride is not open!"
YouNeedATicket: "&cYou need a (correct) ticket to use the FastPass row!"
Succes: "&aHave fun in this ride!"
Malfunction:
ReasonQuestion: "&aPlease type the reason of the malfunction! (Type STOP to set it to Unknown)"
Reported: "&aThe malfunction has been reported to the Technical Service!"
Fixed: "&aThe malfunction has succesfully been removed!"
NotAllowedToChange: "&cYou can't change the status if a ride has a malfunction!"
WaitingRows:
WrongLocation: "&cA waitingrow sign (from the attraction %AttractionID%) couldn't be found! It will be deleted."
WrongAttraction: "&cThat attraction doesn't exists!"
ForgotSelection: "&cYou forgot to select a region! Please select a point one (left) and point two (right) with a STICK."
PosOneSelected: "&aSuccesfully selected position one!"
PosTwoSelected: "&aSuccesfully selected position two!"
SignCreated: "&aYou've succesfully created a WaitingRow sign!"

View file

@ -0,0 +1,13 @@
name: ThemeParkPlus
version: ${project.version}
main: nl.sbdeveloper.themeparkplus.ThemeParkPlus
api-version: "1.13"
authors: [SBDeveloper]
softdepend: [Vault, ThemePark, WorldEdit]
description: Plus version of ThemePark!
website: https://sbdplugins.nl
commands:
themeparkplus:
description: The ThemeParkPlus command!
permission: tpp.command
aliases: ['tpp', 'themeparkp']