mirror of
https://github.com/FancyInnovations/FancyPlugins.git
synced 2025-12-06 07:43:36 +00:00
Add libs
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "9.0.0-beta9" apply false
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.14" apply false
|
||||
id("xyz.jpenilla.run-paper") version "2.3.1" apply false
|
||||
id("net.minecrell.plugin-yml.paper") version "0.6.0" apply false
|
||||
id("io.papermc.hangar-publish-plugin") version "0.1.2" apply false
|
||||
id("com.modrinth.minotaur") version "2.+" apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "de.oliver"
|
||||
description = "Minecraft plugins of FancyInnovations"
|
||||
|
||||
3
gradle.properties
Normal file
3
gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
122
libraries/common/.gitignore
vendored
Normal file
122
libraries/common/.gitignore
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
# User-specific stuff
|
||||
.idea/
|
||||
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# Eclipse
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
plugin/bin/
|
||||
api/bin/
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Package Files #
|
||||
*.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/
|
||||
build
|
||||
.gradle
|
||||
/*.jar
|
||||
13
libraries/common/README.md
Normal file
13
libraries/common/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# How to use
|
||||
|
||||
```kotlin
|
||||
repositories {
|
||||
maven("https://repo.fancyplugins.de/releases/")
|
||||
// or
|
||||
maven("https://repo.fancyplugins.de/snapshots/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("de.oliver:FancyLib:<version>")
|
||||
}
|
||||
```
|
||||
91
libraries/common/build.gradle.kts
Normal file
91
libraries/common/build.gradle.kts
Normal file
@@ -0,0 +1,91 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow")
|
||||
}
|
||||
|
||||
group = "de.oliver"
|
||||
version = "35"
|
||||
description = "Library for all Fancy plugins"
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://repo.fancyplugins.de/releases")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("dev.folia:folia-api:1.20.4-R0.1-SNAPSHOT")
|
||||
compileOnly("de.oliver.FancyAnalytics:logger:0.0.5")
|
||||
|
||||
// database drivers
|
||||
compileOnly("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
compileOnly("mysql:mysql-connector-java:8.0.33")
|
||||
|
||||
// testing
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.3")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.1")
|
||||
testImplementation("com.google.code.gson:gson:2.11.0")
|
||||
}
|
||||
|
||||
tasks {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "fancypluginsReleases"
|
||||
url = uri("https://repo.fancyplugins.de/releases")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "fancypluginsSnapshots"
|
||||
url = uri("https://repo.fancyplugins.de/snapshots")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
from(project.components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
|
||||
// Set the release flag. This configures what version bytecode the compiler will emit, as well as what JDK APIs are usable.
|
||||
// See https://openjdk.java.net/jeps/247 for more information.
|
||||
options.release.set(17)
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
}
|
||||
processResources {
|
||||
filteringCharset = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
public class ConfigHelper {
|
||||
|
||||
public static Object getOrDefault(FileConfiguration config, String path, Object defaultVal) {
|
||||
if (!config.contains(path)) {
|
||||
config.set(path, defaultVal);
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
return config.get(path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import de.oliver.fancyanalytics.logger.ExtendedFancyLogger;
|
||||
import de.oliver.fancylib.gui.inventoryClick.InventoryClickListener;
|
||||
import de.oliver.fancylib.gui.inventoryClick.impl.CancelInventoryItemClick;
|
||||
import de.oliver.fancylib.gui.inventoryClick.impl.ChangePageInventoryItemClick;
|
||||
import de.oliver.fancylib.itemClick.PlayerInteractListener;
|
||||
import de.oliver.fancylib.serverSoftware.ServerSoftware;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.BukkitScheduler;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.FoliaScheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public class FancyLib {
|
||||
|
||||
private static FancyLib instance;
|
||||
private static ExtendedFancyLogger logger = new ExtendedFancyLogger("FancyLib");
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final FancyScheduler scheduler;
|
||||
|
||||
public FancyLib(JavaPlugin plugin) {
|
||||
instance = this;
|
||||
this.plugin = plugin;
|
||||
this.scheduler = ServerSoftware.isFolia()
|
||||
? new FoliaScheduler(plugin)
|
||||
: new BukkitScheduler(plugin);
|
||||
}
|
||||
|
||||
public static FancyLib getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static ExtendedFancyLogger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the listeners for the inventory click and player interact events.
|
||||
*/
|
||||
public void registerListeners() {
|
||||
CancelInventoryItemClick.INSTANCE.register();
|
||||
ChangePageInventoryItemClick.INSTANCE.register();
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new InventoryClickListener(), plugin);
|
||||
Bukkit.getPluginManager().registerEvents(new PlayerInteractListener(), plugin);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public FancyScheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public JavaPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
111
libraries/common/src/main/java/de/oliver/fancylib/FileUtils.java
Normal file
111
libraries/common/src/main/java/de/oliver/fancylib/FileUtils.java
Normal file
@@ -0,0 +1,111 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static String getSHA256Checksum(File file) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
byte[] byteArray = new byte[1024];
|
||||
int bytesCount;
|
||||
|
||||
// Read the file data and update the MessageDigest
|
||||
while ((bytesCount = fis.read(byteArray)) != -1) {
|
||||
digest.update(byteArray, 0, bytesCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the final hash bytes
|
||||
byte[] hashBytes = digest.digest();
|
||||
|
||||
// Convert hash bytes to hex format
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte hashByte : hashBytes) {
|
||||
String hex = Integer.toHexString(0xff & hashByte);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
return hexString.toString();
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public static File findFirstFileByName(File directory, String name) {
|
||||
File[] files = directory.listFiles();
|
||||
if (files == null) {
|
||||
return null;
|
||||
}
|
||||
for (File file : files) {
|
||||
if (file.getName().toLowerCase().contains(name.toLowerCase())) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String readResource(String name) {
|
||||
URL url = getClass().getClassLoader().getResource(name);
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
URLConnection connection = null;
|
||||
try {
|
||||
connection = url.openConnection();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
connection.setUseCaches(false);
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
byte[] file_raw = new byte[inputStream.available()];
|
||||
inputStream.read(file_raw);
|
||||
inputStream.close();
|
||||
return new String(file_raw, StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void saveFile(Plugin plugin, String name) {
|
||||
URL url = getClass().getClassLoader().getResource(name);
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
File file = new File(plugin.getDataFolder() + File.separator + name);
|
||||
if (file.exists()) return;
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
URLConnection connection = null;
|
||||
try {
|
||||
connection = url.openConnection();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
connection.setUseCaches(false);
|
||||
try (FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||
int read;
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((read = inputStream.read(bytes)) != -1) {
|
||||
outputStream.write(bytes, 0, read);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Deprecated
|
||||
public class MessageHelper {
|
||||
private static String primaryColor = "#59bdff";
|
||||
private static String secondaryColor = "#6696e3";
|
||||
private static String successColor = "#81e366";
|
||||
private static String warningColor = "#e3ca66";
|
||||
private static String errorColor = "#e36666";
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull String transform(@NotNull String message) {
|
||||
message = message.replace("<primaryColor>", "<color:" + primaryColor + ">")
|
||||
.replace("<secondaryColor>", "<color:" + secondaryColor + ">")
|
||||
.replace("<successColor>", "<color:" + successColor + ">")
|
||||
.replace("<warningColor>", "<color:" + warningColor + ">")
|
||||
.replace("<errorColor>", "<color:" + errorColor + ">");
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull Component send(@Nullable CommandSender receiver, @NotNull String message) {
|
||||
Component msg = MiniMessage.miniMessage().deserialize(transform(message));
|
||||
if (receiver != null) {
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull Component info(@Nullable CommandSender receiver, @NotNull String message) {
|
||||
Component msg = MiniMessage.miniMessage().deserialize(transform("<primaryColor>" + message));
|
||||
if (receiver != null) {
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull Component success(@Nullable CommandSender receiver, @NotNull String message) {
|
||||
Component msg = MiniMessage.miniMessage().deserialize(transform("<successColor>" + message));
|
||||
if (receiver != null) {
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull Component warning(@Nullable CommandSender receiver, @NotNull String message) {
|
||||
Component msg = MiniMessage.miniMessage().deserialize(transform("<warningColor>" + message));
|
||||
if (receiver != null) {
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @NotNull Component error(@Nullable CommandSender receiver, @NotNull String message) {
|
||||
Component msg = MiniMessage.miniMessage().deserialize(transform("<errorColor>" + message));
|
||||
if (receiver != null) {
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getPrimaryColor() {
|
||||
return primaryColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setPrimaryColor(String primaryColor) {
|
||||
MessageHelper.primaryColor = primaryColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getSecondaryColor() {
|
||||
return secondaryColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setSecondaryColor(String secondaryColor) {
|
||||
MessageHelper.secondaryColor = secondaryColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getSuccessColor() {
|
||||
return successColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setSuccessColor(String successColor) {
|
||||
MessageHelper.successColor = successColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getWarningColor() {
|
||||
return warningColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setWarningColor(String warningColor) {
|
||||
MessageHelper.warningColor = warningColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String getErrorColor() {
|
||||
return errorColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void setErrorColor(String errorColor) {
|
||||
MessageHelper.errorColor = errorColor;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Component removeDecoration(Component component, TextDecoration decoration) {
|
||||
return component.decoration(decoration, TextDecoration.State.FALSE);
|
||||
}
|
||||
}
|
||||
881
libraries/common/src/main/java/de/oliver/fancylib/Metrics.java
Normal file
881
libraries/common/src/main/java/de/oliver/fancylib/Metrics.java
Normal file
@@ -0,0 +1,881 @@
|
||||
/*
|
||||
* This Metrics class was auto-generated and can be copied into your project if you are
|
||||
* not using a build tool like Gradle or Maven for dependency management.
|
||||
*
|
||||
* IMPORTANT: You are not allowed to modify this class, except changing the package.
|
||||
*
|
||||
* Disallowed modifications include but are not limited to:
|
||||
* - Remove the option for users to opt-out
|
||||
* - Change the frequency for data submission
|
||||
* - Obfuscate the code (every obfuscator should allow you to make an exception for specific files)
|
||||
* - Reformat the code (if you use a linter, add an exception)
|
||||
*
|
||||
* Violations will result in a ban of your plugin and account from bStats.
|
||||
*/
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
private final MetricsBase metricsBase;
|
||||
|
||||
/**
|
||||
* Creates a new Metrics instance.
|
||||
*
|
||||
* @param plugin Your plugin instance.
|
||||
* @param serviceId The id of the service. It can be found at <a
|
||||
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(JavaPlugin plugin, int serviceId) {
|
||||
this.plugin = plugin;
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true);
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
config.addDefault("logFailedRequests", false);
|
||||
config.addDefault("logSentData", false);
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
// Inform the server owners about bStats
|
||||
config
|
||||
.options()
|
||||
.header(
|
||||
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
|
||||
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
|
||||
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
|
||||
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
|
||||
+ "anonymous.")
|
||||
.copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
// Load the data
|
||||
boolean enabled = config.getBoolean("enabled", true);
|
||||
String serverUUID = config.getString("serverUuid");
|
||||
boolean logErrors = config.getBoolean("logFailedRequests", false);
|
||||
boolean logSentData = config.getBoolean("logSentData", false);
|
||||
boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
metricsBase =
|
||||
new MetricsBase(
|
||||
"bukkit",
|
||||
serverUUID,
|
||||
serviceId,
|
||||
enabled,
|
||||
this::appendPlatformData,
|
||||
this::appendServiceData,
|
||||
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
|
||||
plugin::isEnabled,
|
||||
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
|
||||
(message) -> this.plugin.getLogger().log(Level.INFO, message),
|
||||
logErrors,
|
||||
logSentData,
|
||||
logResponseStatusText);
|
||||
}
|
||||
|
||||
/** Shuts down the underlying scheduler service. */
|
||||
public void shutdown() {
|
||||
metricsBase.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
metricsBase.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void appendPlatformData(JsonObjectBuilder builder) {
|
||||
builder.appendField("playerAmount", getPlayerAmount());
|
||||
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
|
||||
builder.appendField("bukkitVersion", Bukkit.getVersion());
|
||||
builder.appendField("bukkitName", Bukkit.getName());
|
||||
builder.appendField("javaVersion", System.getProperty("java.version"));
|
||||
builder.appendField("osName", System.getProperty("os.name"));
|
||||
builder.appendField("osArch", System.getProperty("os.arch"));
|
||||
builder.appendField("osVersion", System.getProperty("os.version"));
|
||||
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
private void appendServiceData(JsonObjectBuilder builder) {
|
||||
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
|
||||
}
|
||||
|
||||
private int getPlayerAmount() {
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed from an array to a collection,
|
||||
// This fixes java.lang.NoSuchMethodError:
|
||||
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
return onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception e) {
|
||||
// Just use the new method if the reflection failed
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetricsBase {
|
||||
|
||||
/** The version of the Metrics class. */
|
||||
public static final String METRICS_VERSION = "3.0.2";
|
||||
|
||||
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private final String platform;
|
||||
|
||||
private final String serverUuid;
|
||||
|
||||
private final int serviceId;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
|
||||
|
||||
private final Consumer<Runnable> submitTaskConsumer;
|
||||
|
||||
private final Supplier<Boolean> checkServiceEnabledSupplier;
|
||||
|
||||
private final BiConsumer<String, Throwable> errorLogger;
|
||||
|
||||
private final Consumer<String> infoLogger;
|
||||
|
||||
private final boolean logErrors;
|
||||
|
||||
private final boolean logSentData;
|
||||
|
||||
private final boolean logResponseStatusText;
|
||||
|
||||
private final Set<CustomChart> customCharts = new HashSet<>();
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Creates a new MetricsBase class instance.
|
||||
*
|
||||
* @param platform The platform of the service.
|
||||
* @param serviceId The id of the service.
|
||||
* @param serverUuid The server uuid.
|
||||
* @param enabled Whether or not data sending is enabled.
|
||||
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all platform-specific data.
|
||||
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all service-specific data.
|
||||
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
|
||||
* used to delegate the data collection to a another thread to prevent errors caused by
|
||||
* concurrency. Can be {@code null}.
|
||||
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
|
||||
* @param errorLogger A consumer that accepts log message and an error.
|
||||
* @param infoLogger A consumer that accepts info log messages.
|
||||
* @param logErrors Whether or not errors should be logged.
|
||||
* @param logSentData Whether or not the sent data should be logged.
|
||||
* @param logResponseStatusText Whether or not the response status text should be logged.
|
||||
*/
|
||||
public MetricsBase(
|
||||
String platform,
|
||||
String serverUuid,
|
||||
int serviceId,
|
||||
boolean enabled,
|
||||
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
|
||||
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
|
||||
Consumer<Runnable> submitTaskConsumer,
|
||||
Supplier<Boolean> checkServiceEnabledSupplier,
|
||||
BiConsumer<String, Throwable> errorLogger,
|
||||
Consumer<String> infoLogger,
|
||||
boolean logErrors,
|
||||
boolean logSentData,
|
||||
boolean logResponseStatusText) {
|
||||
ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(1, task -> new Thread(task, "bStats-Metrics"));
|
||||
// We want delayed tasks (non-periodic) that will execute in the future to be
|
||||
// cancelled when the scheduler is shutdown.
|
||||
// Otherwise, we risk preventing the server from shutting down even when
|
||||
// MetricsBase#shutdown() is called
|
||||
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
this.scheduler = scheduler;
|
||||
this.platform = platform;
|
||||
this.serverUuid = serverUuid;
|
||||
this.serviceId = serviceId;
|
||||
this.enabled = enabled;
|
||||
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
|
||||
this.appendServiceDataConsumer = appendServiceDataConsumer;
|
||||
this.submitTaskConsumer = submitTaskConsumer;
|
||||
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
|
||||
this.errorLogger = errorLogger;
|
||||
this.infoLogger = infoLogger;
|
||||
this.logErrors = logErrors;
|
||||
this.logSentData = logSentData;
|
||||
this.logResponseStatusText = logResponseStatusText;
|
||||
checkRelocation();
|
||||
if (enabled) {
|
||||
// WARNING: Removing the option to opt-out will get your plugin banned from
|
||||
// bStats
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
this.customCharts.add(chart);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
scheduler.shutdown();
|
||||
}
|
||||
|
||||
private void startSubmitting() {
|
||||
final Runnable submitTask =
|
||||
() -> {
|
||||
if (!enabled || !checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown();
|
||||
return;
|
||||
}
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept(this::submitData);
|
||||
} else {
|
||||
this.submitData();
|
||||
}
|
||||
};
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven
|
||||
// distribution of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into
|
||||
// the initial and second delay.
|
||||
// WARNING: You must not modify and part of this Metrics class, including the
|
||||
// submit delay or frequency!
|
||||
// WARNING: Modifying this code will get your plugin banned on bStats. Just
|
||||
// don't do it!
|
||||
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
|
||||
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
|
||||
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
|
||||
scheduler.scheduleAtFixedRate(
|
||||
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void submitData() {
|
||||
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder);
|
||||
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder);
|
||||
JsonObjectBuilder.JsonObject[] chartData =
|
||||
customCharts.stream()
|
||||
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(JsonObjectBuilder.JsonObject[]::new);
|
||||
serviceJsonBuilder.appendField("id", serviceId);
|
||||
serviceJsonBuilder.appendField("customCharts", chartData);
|
||||
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
|
||||
baseJsonBuilder.appendField("serverUUID", serverUuid);
|
||||
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
|
||||
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
|
||||
scheduler.execute(
|
||||
() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Could not submit bStats metrics data", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
|
||||
if (logSentData) {
|
||||
infoLogger.accept("Sent bStats metrics data: " + data.toString());
|
||||
}
|
||||
String url = String.format(REPORT_URL, platform);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
|
||||
connection.setDoOutput(true);
|
||||
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (BufferedReader bufferedReader =
|
||||
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
if (logResponseStatusText) {
|
||||
infoLogger.accept("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks that the class was properly relocated. */
|
||||
private void checkRelocation() {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null
|
||||
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this
|
||||
// little "trick" ... :D
|
||||
final String defaultPackage =
|
||||
new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
|
||||
final String examplePackage =
|
||||
new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure no one just copy & pastes the example and uses the wrong
|
||||
// package names
|
||||
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|
||||
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given string.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped string.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()});
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CustomChart {
|
||||
|
||||
private final String chartId;
|
||||
|
||||
protected CustomChart(String chartId) {
|
||||
if (chartId == null) {
|
||||
throw new IllegalArgumentException("chartId must not be null");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
public JsonObjectBuilder.JsonObject getRequestJsonObject(
|
||||
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
|
||||
JsonObjectBuilder builder = new JsonObjectBuilder();
|
||||
builder.appendField("chartId", chartId);
|
||||
try {
|
||||
JsonObjectBuilder.JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
builder.appendField("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
|
||||
}
|
||||
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An extremely simple JSON builder.
|
||||
*
|
||||
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
|
||||
* for its use-case.
|
||||
*/
|
||||
public static class JsonObjectBuilder {
|
||||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
|
||||
private boolean hasAtLeastOneField = false;
|
||||
|
||||
public JsonObjectBuilder() {
|
||||
builder.append("{");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a null field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendNull(String key) {
|
||||
appendFieldUnescaped(key, "null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("JSON value must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int value) {
|
||||
appendFieldUnescaped(key, String.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param object The object.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject object) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("JSON object must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, object.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The string array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values)
|
||||
.map(value -> "\"" + escape(value) + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a field to the object.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param escapedValue The escaped value of the field.
|
||||
*/
|
||||
private void appendFieldUnescaped(String key, String escapedValue) {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("JSON key must not be null");
|
||||
}
|
||||
if (hasAtLeastOneField) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
|
||||
hasAtLeastOneField = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the JSON string and invalidates this builder.
|
||||
*
|
||||
* @return The built JSON string.
|
||||
*/
|
||||
public JsonObject build() {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
JsonObject object = new JsonObject(builder.append("}").toString());
|
||||
builder = null;
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
|
||||
*
|
||||
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
|
||||
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
|
||||
*
|
||||
* @param value The value to escape.
|
||||
* @return The escaped value.
|
||||
*/
|
||||
private static String escape(String value) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '"') {
|
||||
builder.append("\\\"");
|
||||
} else if (c == '\\') {
|
||||
builder.append("\\\\");
|
||||
} else if (c <= '\u000F') {
|
||||
builder.append("\\u000").append(Integer.toHexString(c));
|
||||
} else if (c <= '\u001F') {
|
||||
builder.append("\\u00").append(Integer.toHexString(c));
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A super simple representation of a JSON object.
|
||||
*
|
||||
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
|
||||
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
|
||||
* JsonObject)}.
|
||||
*/
|
||||
public static class JsonObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
private JsonObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class RandomUtils {
|
||||
|
||||
public static boolean random(double percentage) {
|
||||
if (ThreadLocalRandom.current().nextDouble(0, 100) <= percentage) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static double randomInRange(double min, double max) {
|
||||
return (ThreadLocalRandom.current().nextDouble() * (max - min)) + min;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
public static Object getValue(Object instance, String name) {
|
||||
Object result = null;
|
||||
|
||||
try {
|
||||
Field field = instance.getClass().getDeclaredField(name);
|
||||
|
||||
field.setAccessible(true);
|
||||
result = field.get(instance);
|
||||
field.setAccessible(false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Object getStaticValue(Class clazz, String name) {
|
||||
Object result = null;
|
||||
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
|
||||
field.setAccessible(true);
|
||||
result = field.get(clazz);
|
||||
field.setAccessible(false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setValue(Object instance, String name, Object value) {
|
||||
try {
|
||||
Field field = instance.getClass().getDeclaredField(name);
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(instance, value);
|
||||
field.setAccessible(false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
/*
|
||||
From: https://gist.github.com/Jofkos/d0c469528b032d820f42
|
||||
*/
|
||||
|
||||
public class UUIDFetcher {
|
||||
|
||||
/**
|
||||
* Date when name changes were introduced
|
||||
*
|
||||
* @see UUIDFetcher#getUUIDAt(String, long)
|
||||
*/
|
||||
public static final long FEBRUARY_2015 = 1422748800000L;
|
||||
private static final String UUID_URL = "https://api.mojang.com/users/profiles/minecraft/%s?at=%d";
|
||||
private static final String NAME_URL = "https://api.mojang.com/user/profile/%s";
|
||||
private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
|
||||
private static Map<String, UUID> uuidCache = new HashMap<String, UUID>();
|
||||
private static Map<UUID, String> nameCache = new HashMap<UUID, String>();
|
||||
|
||||
private static ExecutorService pool = Executors.newCachedThreadPool();
|
||||
|
||||
private String name;
|
||||
private UUID id;
|
||||
|
||||
/**
|
||||
* Fetches the uuid asynchronously and passes it to the consumer
|
||||
*
|
||||
* @param name The name
|
||||
* @param action Do what you want to do with the uuid her
|
||||
*/
|
||||
public static void getUUID(String name, Consumer<UUID> action) {
|
||||
pool.execute(() -> action.accept(getUUID(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the uuid synchronously and returns it
|
||||
*
|
||||
* @param name The name
|
||||
* @return The uuid
|
||||
*/
|
||||
public static UUID getUUID(String name) {
|
||||
return getUUIDAt(name, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the uuid synchronously for a specified name and time and passes the result to the consumer
|
||||
*
|
||||
* @param name The name
|
||||
* @param timestamp Time when the player had this name in milliseconds
|
||||
* @param action Do what you want to do with the uuid her
|
||||
*/
|
||||
public static void getUUIDAt(String name, long timestamp, Consumer<UUID> action) {
|
||||
pool.execute(() -> action.accept(getUUIDAt(name, timestamp)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the uuid synchronously for a specified name and time
|
||||
*
|
||||
* @param name The name
|
||||
* @param timestamp Time when the player had this name in milliseconds
|
||||
* @see UUIDFetcher#FEBRUARY_2015
|
||||
*/
|
||||
public static UUID getUUIDAt(String name, long timestamp) {
|
||||
name = name.toLowerCase();
|
||||
if (uuidCache.containsKey(name)) {
|
||||
return uuidCache.get(name);
|
||||
}
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(UUID_URL, name, timestamp / 1000)).openConnection();
|
||||
connection.setReadTimeout(5000);
|
||||
UUIDFetcher data = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher.class);
|
||||
|
||||
uuidCache.put(name, data.id);
|
||||
nameCache.put(data.id, data.name);
|
||||
|
||||
return data.id;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the name asynchronously and passes it to the consumer
|
||||
*
|
||||
* @param uuid The uuid
|
||||
* @param action Do what you want to do with the name her
|
||||
*/
|
||||
public static void getName(UUID uuid, Consumer<String> action) {
|
||||
pool.execute(() -> action.accept(getName(uuid)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the name synchronously and returns it
|
||||
*
|
||||
* @param uuid The uuid
|
||||
* @return The name
|
||||
*/
|
||||
public static String getName(UUID uuid) {
|
||||
if (nameCache.containsKey(uuid)) {
|
||||
return nameCache.get(uuid);
|
||||
}
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(String.format(NAME_URL, UUIDTypeAdapter.fromUUID(uuid))).openConnection();
|
||||
connection.setReadTimeout(5000);
|
||||
UUIDFetcher currentNameData = gson.fromJson(new BufferedReader(new InputStreamReader(connection.getInputStream())), UUIDFetcher.class);
|
||||
|
||||
uuidCache.put(currentNameData.name.toLowerCase(), uuid);
|
||||
nameCache.put(uuid, currentNameData.name);
|
||||
|
||||
return currentNameData.name;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UUIDTypeAdapter extends TypeAdapter<UUID> {
|
||||
public static String fromUUID(UUID value) {
|
||||
return value.toString().replace("-", "");
|
||||
}
|
||||
|
||||
public static UUID fromString(String input) {
|
||||
return UUID.fromString(input.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
||||
}
|
||||
|
||||
public void write(JsonWriter out, UUID value) throws IOException {
|
||||
out.value(fromUUID(value));
|
||||
}
|
||||
|
||||
public UUID read(JsonReader in) throws IOException {
|
||||
return fromString(in.nextString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package de.oliver.fancylib;
|
||||
|
||||
import de.oliver.fancylib.versionFetcher.VersionFetcher;
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class VersionConfig {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final VersionFetcher fetcher;
|
||||
private String version;
|
||||
private String build;
|
||||
private String hash;
|
||||
|
||||
public VersionConfig(Plugin plugin, VersionFetcher fetcher) {
|
||||
this.plugin = plugin;
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
try {
|
||||
config.loadFromString(new FileUtils().readResource("version.yml"));
|
||||
} catch (InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
version = config.getString("version");
|
||||
build = config.getString("build");
|
||||
hash = config.getString("hash");
|
||||
}
|
||||
|
||||
public void checkVersionAndDisplay(CommandSender sender, boolean displayOnlyIfOutdated) {
|
||||
String newestVersion = usingLatestVersion();
|
||||
|
||||
if (newestVersion == null) {
|
||||
MessageHelper.error(sender, "Could not fetch latest version");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newestVersion.isEmpty()) {
|
||||
MessageHelper.warning(sender, outdatedVersion(newestVersion, fetcher.getDownloadUrl()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!displayOnlyIfOutdated) {
|
||||
MessageHelper.success(sender, latestVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if could not fetch, empty string if it's the newest, the newest version if it's not the current
|
||||
*/
|
||||
private String usingLatestVersion() {
|
||||
ComparableVersion newestVersion = fetcher.fetchNewestVersion();
|
||||
ComparableVersion currentVersion = new ComparableVersion(version);
|
||||
if (newestVersion == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (newestVersion.compareTo(currentVersion) <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return newestVersion.toString();
|
||||
}
|
||||
|
||||
private String latestVersion() {
|
||||
String result = "This server is using the latest version of {plugin}!\n" +
|
||||
"Version: {version} (Git: {hash})" +
|
||||
"{build}";
|
||||
|
||||
result = result.replace("{plugin}", plugin.getName())
|
||||
.replace("{version}", version)
|
||||
.replace("{hash}", hash.substring(0, 7))
|
||||
.replace("{build}", build.equalsIgnoreCase("undefined") ? "" : "\nBuild: " + build);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String outdatedVersion(String latestVersion, String downloadUrl) {
|
||||
String result = "This server is using an outdated version of {plugin}\n" +
|
||||
"Current version: {current_ver}\n" +
|
||||
"Latest version: {latest_ver}\n" +
|
||||
"Download latest version: <click:open_url:'{download_url}'><u>click here</u></click>";
|
||||
|
||||
result = result.replace("{plugin}", plugin.getName())
|
||||
.replace("{current_ver}", version)
|
||||
.replace("{latest_ver}", latestVersion)
|
||||
.replace("{download_url}", downloadUrl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package de.oliver.fancylib.databases;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
public interface Database {
|
||||
|
||||
/**
|
||||
* Connects to the database
|
||||
*
|
||||
* @return true if success, false if failed
|
||||
*/
|
||||
boolean connect();
|
||||
|
||||
/**
|
||||
* Closes the database connection
|
||||
*
|
||||
* @return true if success, false if failed
|
||||
*/
|
||||
boolean close();
|
||||
|
||||
/**
|
||||
* @return true if connected, false if not
|
||||
*/
|
||||
boolean isConnected();
|
||||
|
||||
/**
|
||||
* @return the connection object, null if not connected
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* Executes a statement on the database
|
||||
*
|
||||
* @return true if success, false if failed
|
||||
*/
|
||||
boolean executeNonQuery(String sql);
|
||||
|
||||
/**
|
||||
* Executes a query on the database
|
||||
*
|
||||
* @return the result or null if failed
|
||||
*/
|
||||
ResultSet executeQuery(String query);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package de.oliver.fancylib.databases;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
public class MySqlDatabase implements Database {
|
||||
|
||||
protected final String host;
|
||||
protected final String port;
|
||||
protected final String database;
|
||||
protected final String username;
|
||||
protected final String password;
|
||||
protected Connection connection;
|
||||
|
||||
public MySqlDatabase(String host, String port, String database, String username, String password) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.database = database;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.connection = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect() {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Class.forName("com.mysql/.jdbc.Driver");
|
||||
connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database, username, password);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
try {
|
||||
if (!isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
connection.close();
|
||||
connection = null;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return connection != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeNonQuery(String sql) {
|
||||
try {
|
||||
connection.createStatement().execute(sql);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery(String query) {
|
||||
try {
|
||||
ResultSet resultSet = connection.createStatement().executeQuery(query);
|
||||
return resultSet;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.oliver.fancylib.databases;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
public class SqliteDatabase extends MySqlDatabase {
|
||||
|
||||
protected final String path;
|
||||
protected File file;
|
||||
|
||||
public SqliteDatabase(String path) {
|
||||
super(null, null, null, null, null);
|
||||
this.path = path;
|
||||
this.file = new File(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect() {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
if (!file.createNewFile()) {
|
||||
Bukkit.getLogger().warning("Could not create database file.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + file.getPath());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.oliver.fancylib.featureFlags;
|
||||
|
||||
public class FeatureFlag {
|
||||
|
||||
private final String name;
|
||||
private final String description;
|
||||
private boolean enabled;
|
||||
private final boolean forceDisabled;
|
||||
|
||||
public FeatureFlag(String name, String description, boolean forceDisabled) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.forceDisabled = forceDisabled;
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
if(forceDisabled) return false;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isForceDisabled() {
|
||||
return forceDisabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package de.oliver.fancylib.featureFlags;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FeatureFlagConfig {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final File configFile;
|
||||
private final List<FeatureFlag> featureFlags;
|
||||
|
||||
public FeatureFlagConfig(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.configFile = new File("plugins" + File.separator + plugin.getName() + File.separator + "featureFlags.yml");
|
||||
this.featureFlags = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
if (!configFile.exists()) {
|
||||
try {
|
||||
new File(configFile.getParent()).mkdirs();
|
||||
configFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
for (FeatureFlag featureFlag : featureFlags) {
|
||||
config.setInlineComments("feature-flags." + featureFlag.getName(), List.of(featureFlag.getDescription()));
|
||||
|
||||
if (config.isSet("feature-flags." + featureFlag.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
config.set("feature-flags." + featureFlag.getName(), false);
|
||||
}
|
||||
|
||||
for (String flagName : config.getConfigurationSection("feature-flags").getKeys(false)) {
|
||||
boolean enabled = config.getBoolean("feature-flags." + flagName, false);
|
||||
FeatureFlag flag = getFeatureFlag(flagName);
|
||||
if (flag == null) {
|
||||
flag = new FeatureFlag(flagName, "", false);
|
||||
featureFlags.add(flag);
|
||||
}
|
||||
|
||||
flag.setEnabled(enabled);
|
||||
}
|
||||
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public FeatureFlag getFeatureFlag(String name) {
|
||||
for (FeatureFlag featureFlag : featureFlags) {
|
||||
if (featureFlag.getName().equalsIgnoreCase(name.toLowerCase())) {
|
||||
return featureFlag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addFeatureFlag(FeatureFlag featureFlag) {
|
||||
if (!featureFlags.contains(featureFlag)) {
|
||||
featureFlags.add(featureFlag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package de.oliver.fancylib.gui.customInventories;
|
||||
|
||||
import de.oliver.fancylib.gui.inventoryClick.InventoryItemClick;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class CustomPlayerInventory implements InventoryHolder {
|
||||
|
||||
protected final Player player;
|
||||
protected Inventory inventory;
|
||||
|
||||
protected CustomPlayerInventory(Player player, int amountRows, Component title) {
|
||||
this.player = player;
|
||||
this.inventory = Bukkit.createInventory(this, amountRows * 9, title);
|
||||
}
|
||||
|
||||
public static ItemStack getPlaceholder() {
|
||||
ItemStack item = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||
item.editMeta(itemMeta -> {
|
||||
itemMeta.displayName(Component.empty());
|
||||
itemMeta.getPersistentDataContainer().set(InventoryItemClick.ON_CLICK_KEY, PersistentDataType.STRING, "cancelClick");
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
player.openInventory(inventory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.oliver.fancylib.gui.customInventories;
|
||||
|
||||
import de.oliver.fancylib.FancyLib;
|
||||
import de.oliver.fancylib.MessageHelper;
|
||||
import de.oliver.fancylib.gui.inventoryClick.InventoryItemClick;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public interface PageInventory {
|
||||
|
||||
NamespacedKey PAGE_KEY = new NamespacedKey(FancyLib.getInstance().getPlugin(), "page");
|
||||
|
||||
static ItemStack previousPage(int currentPage) {
|
||||
ItemStack previousPage = new ItemStack(Material.ARROW);
|
||||
previousPage.editMeta(itemMeta -> {
|
||||
itemMeta.displayName(MessageHelper.removeDecoration(MiniMessage.miniMessage().deserialize("<gradient:gold:yellow:gold>Previous page</gradient>"), TextDecoration.ITALIC));
|
||||
|
||||
itemMeta.getPersistentDataContainer().set(PageInventory.PAGE_KEY, PersistentDataType.INTEGER, currentPage - 1);
|
||||
itemMeta.getPersistentDataContainer().set(InventoryItemClick.ON_CLICK_KEY, PersistentDataType.STRING, "changePage");
|
||||
});
|
||||
|
||||
return previousPage;
|
||||
}
|
||||
|
||||
static ItemStack nextPage(int currentPage) {
|
||||
ItemStack nextPage = new ItemStack(Material.ARROW);
|
||||
nextPage.editMeta(itemMeta -> {
|
||||
itemMeta.displayName(MessageHelper.removeDecoration(MiniMessage.miniMessage().deserialize("<gradient:gold:yellow:gold>Next page</gradient>"), TextDecoration.ITALIC));
|
||||
|
||||
itemMeta.getPersistentDataContainer().set(PageInventory.PAGE_KEY, PersistentDataType.INTEGER, currentPage + 1);
|
||||
itemMeta.getPersistentDataContainer().set(InventoryItemClick.ON_CLICK_KEY, PersistentDataType.STRING, "changePage");
|
||||
});
|
||||
|
||||
return nextPage;
|
||||
}
|
||||
|
||||
void loadPage(int page);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.oliver.fancylib.gui.inventoryClick;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public class InventoryClickListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
|
||||
try {
|
||||
ItemStack item = event.getCurrentItem();
|
||||
|
||||
if (item.getItemMeta().getPersistentDataContainer().has(InventoryItemClick.ON_CLICK_KEY)) {
|
||||
String id = item.getItemMeta().getPersistentDataContainer().get(InventoryItemClick.ON_CLICK_KEY, PersistentDataType.STRING);
|
||||
InventoryClickRegistry.getInventoryItemClick(id).onClick(event, (Player) event.getWhoClicked());
|
||||
}
|
||||
|
||||
} catch (NullPointerException ignore) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.oliver.fancylib.gui.inventoryClick;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InventoryClickRegistry {
|
||||
|
||||
private static final Map<String, InventoryItemClick> inventoryItemClickMap = new HashMap<>();
|
||||
|
||||
public static InventoryItemClick getInventoryItemClick(String id) {
|
||||
return inventoryItemClickMap.getOrDefault(id, InventoryItemClick.EMPTY);
|
||||
}
|
||||
|
||||
public static void registerInventoryItemClick(InventoryItemClick inventoryItemClick) {
|
||||
inventoryItemClickMap.put(inventoryItemClick.getId(), inventoryItemClick);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.oliver.fancylib.gui.inventoryClick;
|
||||
|
||||
import de.oliver.fancylib.FancyLib;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface InventoryItemClick {
|
||||
|
||||
NamespacedKey ON_CLICK_KEY = new NamespacedKey(FancyLib.getInstance().getPlugin(), "onclick");
|
||||
|
||||
InventoryItemClick EMPTY = new InventoryItemClick() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(InventoryClickEvent event, Player player) {
|
||||
}
|
||||
};
|
||||
|
||||
static boolean hasKeys(ItemStack item, List<NamespacedKey> keys) {
|
||||
PersistentDataContainer data = item.getItemMeta().getPersistentDataContainer();
|
||||
for (NamespacedKey key : keys) {
|
||||
if (!data.has(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getId();
|
||||
|
||||
void onClick(InventoryClickEvent event, Player player);
|
||||
|
||||
default void register() {
|
||||
InventoryClickRegistry.registerInventoryItemClick(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.oliver.fancylib.gui.inventoryClick.impl;
|
||||
|
||||
import de.oliver.fancylib.gui.inventoryClick.InventoryItemClick;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
|
||||
public class CancelInventoryItemClick implements InventoryItemClick {
|
||||
|
||||
public static final CancelInventoryItemClick INSTANCE = new CancelInventoryItemClick();
|
||||
|
||||
private CancelInventoryItemClick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "cancelClick";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(InventoryClickEvent event, Player player) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package de.oliver.fancylib.gui.inventoryClick.impl;
|
||||
|
||||
import de.oliver.fancylib.gui.customInventories.PageInventory;
|
||||
import de.oliver.fancylib.gui.inventoryClick.InventoryItemClick;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ChangePageInventoryItemClick implements InventoryItemClick {
|
||||
|
||||
public static final ChangePageInventoryItemClick INSTANCE = new ChangePageInventoryItemClick();
|
||||
|
||||
private final static List<NamespacedKey> REQUIRED_KEYS = Collections.singletonList(
|
||||
PageInventory.PAGE_KEY
|
||||
);
|
||||
|
||||
private ChangePageInventoryItemClick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "changePage";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(InventoryClickEvent event, Player player) {
|
||||
ItemStack item = event.getCurrentItem();
|
||||
|
||||
if (item != null && InventoryItemClick.hasKeys(item, REQUIRED_KEYS)) {
|
||||
event.setCancelled(true);
|
||||
|
||||
int page = item.getItemMeta().getPersistentDataContainer().get(PageInventory.PAGE_KEY, PersistentDataType.INTEGER);
|
||||
|
||||
if (event.getInventory().getHolder() == null || !(event.getInventory().getHolder() instanceof PageInventory pageInventory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageInventory.loadPage(page);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.oliver.fancylib.itemClick;
|
||||
|
||||
import de.oliver.fancylib.FancyLib;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
public interface ItemClick {
|
||||
NamespacedKey ON_CLICK_KEY = new NamespacedKey(FancyLib.getInstance().getPlugin(), "oninteract");
|
||||
|
||||
ItemClick EMPTY = new ItemClick() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(PlayerInteractEvent event, Player player) {
|
||||
}
|
||||
};
|
||||
|
||||
String getId();
|
||||
|
||||
void onClick(PlayerInteractEvent event, Player player);
|
||||
|
||||
default void register() {
|
||||
ItemClickRegistry.registerItemClick(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.oliver.fancylib.itemClick;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ItemClickRegistry {
|
||||
|
||||
private static final Map<String, ItemClick> itemClickMap = new HashMap<>();
|
||||
|
||||
public static ItemClick getItemClick(String id) {
|
||||
return itemClickMap.getOrDefault(id, ItemClick.EMPTY);
|
||||
}
|
||||
|
||||
public static void registerItemClick(ItemClick itemClick) {
|
||||
itemClickMap.put(itemClick.getId(), itemClick);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.oliver.fancylib.itemClick;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public class PlayerInteractListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
try {
|
||||
ItemStack item = event.getItem();
|
||||
if (event.getHand() == EquipmentSlot.HAND && item.getItemMeta().getPersistentDataContainer().has(ItemClick.ON_CLICK_KEY)) {
|
||||
String id = item.getItemMeta().getPersistentDataContainer().get(ItemClick.ON_CLICK_KEY, PersistentDataType.STRING);
|
||||
|
||||
ItemClickRegistry.getItemClick(id).onClick(event, event.getPlayer());
|
||||
}
|
||||
} catch (NullPointerException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
137
libraries/common/src/main/java/de/oliver/fancylib/jdb/JDB.java
Normal file
137
libraries/common/src/main/java/de/oliver/fancylib/jdb/JDB.java
Normal file
@@ -0,0 +1,137 @@
|
||||
package de.oliver.fancylib.jdb;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The JDB class provides a simple JSON document-based storage system in a specified directory.
|
||||
*/
|
||||
public class JDB {
|
||||
private final static Gson GSON = new GsonBuilder()
|
||||
.serializeNulls()
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
private static final String FILE_EXTENSION = ".json";
|
||||
private final @NotNull String basePath;
|
||||
private final @NotNull File baseDirectory;
|
||||
|
||||
/**
|
||||
* Constructs a new JDB instance with the specified base path.
|
||||
*
|
||||
* @param basePath the base directory path where documents will be stored
|
||||
*/
|
||||
public JDB(@NotNull String basePath) {
|
||||
this.basePath = basePath;
|
||||
this.baseDirectory = new File(basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a document from the specified path, deserializing it into the given class type.
|
||||
*
|
||||
* @param <T> the type of the object to be returned
|
||||
* @param path the relative path (excluding .json extension) where the document is located
|
||||
* @param clazz the class type to which the document should be deserialized
|
||||
* @return a JDocument containing the deserialized object and its path, or null if the file does not exist
|
||||
* @throws IOException if an I/O error occurs during file reading
|
||||
*/
|
||||
public <T> T get(@NotNull String path, @NotNull Class<T> clazz) throws IOException {
|
||||
File documentFile = new File(baseDirectory, createFilePath(path));
|
||||
if (!documentFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
BufferedReader bufferedReader = Files.newBufferedReader(documentFile.toPath());
|
||||
return GSON.fromJson(bufferedReader, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a document from the specified path.
|
||||
*
|
||||
* @param path the relative path (excluding .json extension) where the document is located
|
||||
* @return a JDocument containing the deserialized data or null if the file does not exist
|
||||
* @throws IOException if an I/O error occurs during file reading
|
||||
*/
|
||||
public JDocument getDocument(@NotNull String path) throws IOException {
|
||||
File documentFile = new File(baseDirectory, createFilePath(path));
|
||||
if (!documentFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
BufferedReader bufferedReader = Files.newBufferedReader(documentFile.toPath());
|
||||
Map<String, Object> data = (Map<String, Object>) GSON.fromJson(bufferedReader, Map.class);
|
||||
return new JDocument(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all documents from the specified directory path, deserializing them into the given class type.
|
||||
*
|
||||
* @param <T> the type of objects to be returned
|
||||
* @param path the relative directory path containing the documents
|
||||
* @param clazz the class type to which the documents should be deserialized
|
||||
* @return a List of JDocument objects containing the deserialized objects and their paths, or null if the directory or files do not exist
|
||||
* @throws IOException if an I/O error occurs during file reading
|
||||
*/
|
||||
public <T> List<T> getAll(@NotNull String path, @NotNull Class<T> clazz) throws IOException {
|
||||
File directory = new File(baseDirectory, path);
|
||||
if (!directory.exists()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
File[] files = directory.listFiles();
|
||||
if (files == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<T> documents = new ArrayList<>(files.length);
|
||||
for (File file : files) {
|
||||
documents.add(get(path + "/" + file.getName().replace(FILE_EXTENSION, ""), clazz));
|
||||
}
|
||||
return documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given value as a document at the specified path.
|
||||
*
|
||||
* @param <T> the type of the object to be saved
|
||||
* @param path the relative path (excluding .json extension) where the document will be saved
|
||||
* @param value the object to be saved as a JSON document
|
||||
* @throws IOException if an I/O error occurs during file writing
|
||||
*/
|
||||
public <T> void set(@NotNull String path, @NotNull T value) throws IOException {
|
||||
File documentFile = new File(baseDirectory, createFilePath(path));
|
||||
if (!documentFile.exists()) {
|
||||
documentFile.getParentFile().mkdirs();
|
||||
documentFile.createNewFile();
|
||||
}
|
||||
String json = GSON.toJson(value);
|
||||
Files.write(documentFile.toPath(), json.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the document(s) at the specified path.
|
||||
*
|
||||
* @param path the relative path (excluding .json extension) where the document(s) are located
|
||||
*/
|
||||
public void delete(@NotNull String path) {
|
||||
File documentFile = new File(baseDirectory, createFilePath(path));
|
||||
if (documentFile.exists()) {
|
||||
documentFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the file path by appending the base path, provided path, and the file extension.
|
||||
*
|
||||
* @param path the relative path (excluding .json extension)
|
||||
* @return the full file path
|
||||
*/
|
||||
private String createFilePath(@NotNull String path) {
|
||||
return path + FILE_EXTENSION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package de.oliver.fancylib.jdb;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a document that holds a map of key-value pairs with support for nested keys.
|
||||
*/
|
||||
public class JDocument {
|
||||
private final @NotNull Map<String, Object> data;
|
||||
|
||||
public JDocument(@NotNull Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from the document using the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the value associated with the given key, or null if the key is not found
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return getValue(key, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the document contains a value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return true if the given key exists in the document, otherwise false
|
||||
*/
|
||||
public boolean contains(String key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the set of keys from a map value associated with a given key in the document.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the map value in the document (e.g. "foo.bar.baz")
|
||||
* @return a set of keys from the map associated with the given key, or an empty set if the key
|
||||
* is not found or the value is not a map
|
||||
*/
|
||||
public Set<String> getKeys(String key) {
|
||||
Map<String, Object> map = (Map<String, Object>) getValue(key, Map.class);
|
||||
return map != null ? map.keySet() : new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a string value from the document using the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the string value associated with the given key, or an empty string if the key is not found or the value is not a string
|
||||
*/
|
||||
public String getString(String key) {
|
||||
return (String) getValueOrDefault(key, String.class, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a boolean value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the boolean value associated with the given key, or false if the key is not found or the value is not a boolean
|
||||
*/
|
||||
public boolean getBoolean(String key) {
|
||||
return (boolean) getValueOrDefault(key, Boolean.class, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a byte value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the byte value associated with the given key, or 0 if the key is not found or the value is not a byte
|
||||
*/
|
||||
public byte getByte(String key) {
|
||||
return (byte) getValueOrDefault(key, Byte.class, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a short value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the short value associated with the given key, or 0 if the key is not found or the value is not a short
|
||||
*/
|
||||
public short getShort(String key) {
|
||||
return (short) getValueOrDefault(key, Short.class, (short) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an integer value associated with the given key from the document.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the integer value associated with the given key, or 0 if the key is not found or the value is not an integer
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
return (int) getValueOrDefault(key, Integer.class, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a long value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the long value associated with the given key, or 0 if the key is not found or the value is not a long
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
return (long) getValueOrDefault(key, Long.class, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a float value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the float value associated with the given key, or 0 if the key is not found or the value is not a float
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
return (float) getValueOrDefault(key, Float.class, 0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a double value associated with the given key.
|
||||
*
|
||||
* @param key the dot-separated key used to locate the value in the document (e.g. "foo.bar.baz")
|
||||
* @return the double value associated with the given key, or 0 if the key is not found or the value is not a double
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
return (double) getValueOrDefault(key, Double.class, 0d);
|
||||
}
|
||||
|
||||
private Object getValue(String key, Class<?> clazz) {
|
||||
String[] parts = key.split("\\.");
|
||||
Map<String, Object> current = data;
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
Object value = current.get(parts[i]);
|
||||
if (value == null || (i < parts.length - 1 && !(value instanceof Map))) {
|
||||
return null;
|
||||
}
|
||||
if (i == parts.length - 1) {
|
||||
return clazz.isInstance(value) ? value : null;
|
||||
}
|
||||
current = (Map<String, Object>) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> T getValueOrDefault(String key, Class<T> clazz, T defaultValue) {
|
||||
T value = (T) getValue(key, clazz);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.oliver.fancylib.serverSoftware;
|
||||
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.BukkitScheduler;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.FoliaScheduler;
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ServerSoftware {
|
||||
|
||||
public static boolean isFolia() {
|
||||
return Arrays.stream(PluginMeta.class.getDeclaredMethods())
|
||||
.map(Method::getName)
|
||||
.anyMatch(s -> s.equals("isFoliaSupported"));
|
||||
}
|
||||
|
||||
public static boolean isPaper() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.event.player.AsyncChatEvent");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBukkit() {
|
||||
try {
|
||||
Class.forName("org.bukkit.Bukkit");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static FancyScheduler getCorrectScheduler(JavaPlugin plugin) {
|
||||
if (isFolia()) {
|
||||
return new FoliaScheduler(plugin);
|
||||
}
|
||||
|
||||
return new BukkitScheduler(plugin);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package de.oliver.fancylib.serverSoftware.schedulers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitScheduler implements FancyScheduler {
|
||||
|
||||
BukkitTask bukkitTask;
|
||||
JavaPlugin plugin;
|
||||
|
||||
public BukkitScheduler(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTask(Location location, Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTask(plugin, task);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskAsynchronously(Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, task);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskLater(Location location, long delay, Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskLater(plugin, task, delay);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskLaterAsynchronously(long delay, Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, task, delay);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskTimer(Location location, long delay, long period, Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskTimer(plugin, task, delay, period);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskTimerAsynchronously(long delay, long period, Runnable task) {
|
||||
bukkitTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, delay, period);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (!bukkitTask.isCancelled()) {
|
||||
bukkitTask.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.oliver.fancylib.serverSoftware.schedulers;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface FancyScheduler {
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param task task...
|
||||
* @param location required for Folia, in Bukkit can be null
|
||||
* @return The created {@link FancyScheduler}.
|
||||
*/
|
||||
@NotNull FancyScheduler runTask(Location location, Runnable task);
|
||||
|
||||
/**
|
||||
* Run the task asynchronously.
|
||||
*
|
||||
* @param task task...
|
||||
* @return The created {@link FancyScheduler}
|
||||
*/
|
||||
@NotNull FancyScheduler runTaskAsynchronously(Runnable task);
|
||||
|
||||
/**
|
||||
* Run the task after a specified number of ticks.
|
||||
*
|
||||
* @param location required for Folia, in Bukkit can be null
|
||||
* @param task task...
|
||||
* @param delay The number of ticks to wait.
|
||||
* @return The created {@link FancyScheduler}
|
||||
*/
|
||||
@NotNull FancyScheduler runTaskLater(Location location, long delay, Runnable task);
|
||||
|
||||
/**
|
||||
* Run the task asynchronously after a specified number of ticks.
|
||||
*
|
||||
* @param task task...
|
||||
* @param delay The number of ticks to wait.
|
||||
* @return The created {@link FancyScheduler}
|
||||
*/
|
||||
@NotNull FancyScheduler runTaskLaterAsynchronously(long delay, Runnable task);
|
||||
|
||||
/**
|
||||
* Run the task repeatedly on a timer.
|
||||
*
|
||||
* @param location required for Folia, in Bukkit can be null
|
||||
* @param task task...
|
||||
* @param delay The delay before the task is first run (in ticks).
|
||||
* @param period The ticks elapsed before the task is run again.
|
||||
* @return The created {@link FancyScheduler}
|
||||
*/
|
||||
@NotNull FancyScheduler runTaskTimer(Location location, long delay, long period, Runnable task);
|
||||
|
||||
/**
|
||||
* Run the task repeatedly on a timer asynchronously.
|
||||
*
|
||||
* @param task task...
|
||||
* @param delay The delay before the task is first run (in ticks).
|
||||
* @param period The ticks elapsed before the task is run again.
|
||||
* @return The created {@link FancyScheduler}
|
||||
*/
|
||||
@NotNull FancyScheduler runTaskTimerAsynchronously(long delay, long period, Runnable task);
|
||||
|
||||
/**
|
||||
* Cancel the task.
|
||||
*/
|
||||
void cancel();
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package de.oliver.fancylib.serverSoftware.schedulers;
|
||||
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FoliaScheduler implements FancyScheduler {
|
||||
private static final long NANOSECONDS_PER_TICK = 50000000L;
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private ScheduledTask scheduledTask;
|
||||
|
||||
public FoliaScheduler(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTask(Location location, Runnable task) {
|
||||
if (location != null) {
|
||||
scheduledTask = plugin.getServer().getRegionScheduler().run(plugin, location, scheduledTask1 -> task.run());
|
||||
} else {
|
||||
scheduledTask = plugin.getServer().getGlobalRegionScheduler().run(plugin, scheduledTask1 -> task.run());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskAsynchronously(Runnable task) {
|
||||
scheduledTask = plugin.getServer().getAsyncScheduler().runNow(plugin, scheduledTask1 -> task.run());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskLater(Location location, long delay, Runnable task) {
|
||||
if (location != null) {
|
||||
scheduledTask = plugin.getServer().getRegionScheduler().runDelayed(plugin, location, scheduledTask1 -> task.run(), delay);
|
||||
} else {
|
||||
scheduledTask = plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, scheduledTask1 -> task.run(), delay);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskLaterAsynchronously(long delay, Runnable task) {
|
||||
scheduledTask = plugin.getServer().getAsyncScheduler().runDelayed(plugin, scheduledTask1 -> task.run(), delay * NANOSECONDS_PER_TICK, TimeUnit.NANOSECONDS);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskTimer(Location location, long delay, long period, Runnable task) {
|
||||
scheduledTask = plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, location, scheduledTask1 -> task.run(), delay, period);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FancyScheduler runTaskTimerAsynchronously(long delay, long period, Runnable task) {
|
||||
scheduledTask = plugin.getServer().getAsyncScheduler().runAtFixedRate(plugin, scheduledTask1 -> task.run(), delay * NANOSECONDS_PER_TICK, period * NANOSECONDS_PER_TICK, TimeUnit.NANOSECONDS);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
if (!scheduledTask.isCancelled()) {
|
||||
scheduledTask.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package de.oliver.fancylib.tests;
|
||||
|
||||
/**
|
||||
* A generic class for making assertions on the expected values.
|
||||
*
|
||||
* @param <T> the type of the value to be asserted.
|
||||
*/
|
||||
public class Expectable<T> {
|
||||
|
||||
/**
|
||||
* The value that is being wrapped by this Expectable instance.
|
||||
* This is the object against which all expectations will be verified.
|
||||
*/
|
||||
private final T t;
|
||||
|
||||
private Expectable(T t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of Expectable for the given value.
|
||||
*
|
||||
* @param <T> the type of the value being tested
|
||||
* @param t the actual value to create an expectation for
|
||||
* @return a new Expectable instance for the given value
|
||||
*/
|
||||
public static <T> Expectable<T> expect(T t) {
|
||||
return new Expectable<>(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the actual value is not null.
|
||||
* <p>
|
||||
* Throws an AssertionError if the value of the field 't' is null,
|
||||
* indicating that the actual value is expected to be non-null.
|
||||
*
|
||||
* @throws AssertionError if the value of the field 't' is null
|
||||
*/
|
||||
public void toBeDefined() {
|
||||
if (t == null) {
|
||||
throw new AssertionError("Expected not null but got null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the value of the field 't' is null.
|
||||
* <p>
|
||||
* Throws an AssertionError if the value of 't' is not null,
|
||||
* indicating the expectation that the value should be null.
|
||||
*
|
||||
* @throws AssertionError if the value of 't' is not null
|
||||
*/
|
||||
public void toBeNull() {
|
||||
if (t != null) {
|
||||
throw new AssertionError("Expected null but got not null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is equal to the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be equal to
|
||||
* @throws AssertionError if the actual value is not equal to the expected value
|
||||
*/
|
||||
public void toBe(T expected) {
|
||||
if (t != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is equal to the expected value using the {@code equals} method.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be equal to
|
||||
* @throws AssertionError if the actual value is not equal to the expected value
|
||||
*/
|
||||
public void toEqual(T expected) {
|
||||
if (!t.equals(expected)) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is greater than the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be greater than
|
||||
* @throws AssertionError if the actual value is not greater than the expected value,
|
||||
* or if the type of the actual value is not one of Integer, Long, Float, or Double
|
||||
*/
|
||||
public void toBeGreaterThan(T expected) {
|
||||
if (t instanceof Integer) {
|
||||
if ((Integer) t <= (Integer) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Long) {
|
||||
if ((Long) t <= (Long) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Float) {
|
||||
if ((Float) t <= (Float) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Double) {
|
||||
if ((Double) t <= (Double) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be greater than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toBeGreaterThan can only be used on Integers, Longs, Floats, and Doubles");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is less than the expected value.
|
||||
*
|
||||
* @param expected the value that the actual value is expected to be less than
|
||||
* @throws AssertionError if the actual value is not less than the expected value,
|
||||
* or if the type of the actual value is not one of Integer, Long, Float, or Double
|
||||
*/
|
||||
public void toBeLessThan(T expected) {
|
||||
if (t instanceof Integer) {
|
||||
if ((Integer) t >= (Integer) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Long) {
|
||||
if ((Long) t >= (Long) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Float) {
|
||||
if ((Float) t >= (Float) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Double) {
|
||||
if ((Double) t >= (Double) expected) {
|
||||
throw new AssertionError("Expected " + t + " to be less than " + expected);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toBeLessThan can only be used on Integers, Longs, Floats, and Doubles");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value is an instance of the expected class.
|
||||
* This method checks whether the value held in the field 't' is an instance of the provided Class.
|
||||
*
|
||||
* @param expected the Class object that the actual value is expected to be an instance of
|
||||
* @throws AssertionError if the actual value is not an instance of the expected class
|
||||
*/
|
||||
public void toBeInstanceOf(Class<?> expected) {
|
||||
if (!expected.isInstance(t)) {
|
||||
throw new AssertionError("Expected " + t + " to be an instance of " + expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given expected value is contained within the actual value.
|
||||
* <p>
|
||||
* This method checks if the expected value is present in a String, Iterable, or Array.
|
||||
* If the actual value is a String, it uses the contains method to check if the expected value
|
||||
* is a substring. If the actual value is an Iterable, it checks if the expected value is an element.
|
||||
* If the actual value is an Array, it checks if the expected value is present in the array.
|
||||
*
|
||||
* @param expected the value that is expected to be contained within the actual value
|
||||
* @throws AssertionError if the expected value is not contained within the actual value
|
||||
*/
|
||||
public void toContain(Object expected) {
|
||||
if (t instanceof String) {
|
||||
if (!((String) t).contains((String) expected)) {
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Iterable) {
|
||||
if (!((Iterable<?>) t).spliterator().tryAdvance(o -> {
|
||||
if (o.equals(expected)) {
|
||||
return;
|
||||
}
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
})) {
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Object[]) {
|
||||
for (Object o : (Object[]) t) {
|
||||
if (o.equals(expected)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("Expected " + expected + " to be contained in " + t);
|
||||
}
|
||||
|
||||
throw new AssertionError("toContain can only be used on Strings, Iterables and Arrays");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual value has the expected length.
|
||||
* This method checks if the actual value is a String, Iterable, or Array,
|
||||
* and compares their length or size to the given expected length.
|
||||
*
|
||||
* @param expected the expected length of the actual value
|
||||
* @throws AssertionError if the actual value does not have the expected length,
|
||||
* or if the actual value is not of type String, Iterable, or Array
|
||||
*/
|
||||
public void toHaveLength(int expected) {
|
||||
if (t instanceof String) {
|
||||
if (((String) t).length() != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((String) t).length());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Iterable) {
|
||||
if (((Iterable<?>) t).spliterator().getExactSizeIfKnown() != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((Iterable<?>) t).spliterator().getExactSizeIfKnown());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (t instanceof Object[]) {
|
||||
if (((Object[]) t).length != expected) {
|
||||
throw new AssertionError("Expected " + expected + " but got " + ((Object[]) t).length);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("toHaveLength can only be used on Strings");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package de.oliver.fancylib.tests;
|
||||
|
||||
import de.oliver.fancylib.tests.annotations.FPAfterEach;
|
||||
import de.oliver.fancylib.tests.annotations.FPBeforeEach;
|
||||
import de.oliver.fancylib.tests.annotations.FPTest;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* FPTestClass is a record that encapsulates information about a test class and its associated test methods.
|
||||
* This class supports running tests annotated with {@link FPTest}.
|
||||
*
|
||||
* @param testClass the test class to run tests for (must be annotated with {@link FPTest})
|
||||
* @param beforeEach the method annotated with {@link FPBeforeEach} to run before each test
|
||||
* @param afterEach the method annotated with {@link FPAfterEach} to run after each test
|
||||
* @param testMethods the list of test methods annotated with {@link FPTest}
|
||||
*/
|
||||
public record FPTestClass(
|
||||
Class<?> testClass,
|
||||
Method beforeEach,
|
||||
Method afterEach,
|
||||
List<Method> testMethods
|
||||
) {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FPTestClass.class.getName());
|
||||
|
||||
/**
|
||||
* Creates an instance of FPTestClass by inspecting the provided test class for methods annotated
|
||||
* with FPTest, FPBeforeEach, and FPAfterEach annotations.
|
||||
* These methods are used to define the setup, teardown, and test methods for the class.
|
||||
*
|
||||
* @param testClass the class to be inspected for annotated methods
|
||||
* @return an instance of FPTestClass containing the test class and its annotated methods
|
||||
*/
|
||||
public static FPTestClass fromClass(Class<?> testClass) {
|
||||
Method beforeEach = null;
|
||||
Method afterEach = null;
|
||||
List<Method> testMethods = new ArrayList<>();
|
||||
|
||||
for (Method method : testClass.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(FPTest.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
testMethods.add(method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(FPBeforeEach.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
beforeEach = method;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.isAnnotationPresent(FPAfterEach.class)) {
|
||||
if (method.getParameterCount() != 1) continue;
|
||||
if (method.getParameterTypes()[0] != Player.class) continue;
|
||||
|
||||
afterEach = method;
|
||||
}
|
||||
}
|
||||
|
||||
return new FPTestClass(testClass, beforeEach, afterEach, testMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the test methods belonging to the test class, performing any necessary setup and teardown operations.
|
||||
*
|
||||
* @param player The player context to pass to the test methods.
|
||||
* @return true if all tests completed successfully, false if any test failed or an unexpected exception occurred.
|
||||
*/
|
||||
public boolean runTests(Player player) {
|
||||
logger.info("Running tests for " + testClass.getSimpleName());
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Running tests for " + testClass.getSimpleName()));
|
||||
|
||||
for (Method testMethod : testMethods) {
|
||||
Object testClassObj;
|
||||
try {
|
||||
testClassObj = testClass.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
logger.warning("Failed to create test class instance: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
FPTest fpTest = testMethod.getAnnotation(FPTest.class);
|
||||
if (fpTest.skip()) {
|
||||
logger.info("Skipping test " + displayName(testMethod));
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<gold>Skipping test " + displayName(testMethod)));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
long testStart = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
if (beforeEach != null) beforeEach.invoke(testClassObj, player);
|
||||
|
||||
testMethod.invoke(testClassObj, player);
|
||||
|
||||
if (afterEach != null) afterEach.invoke(testClassObj, player);
|
||||
} catch (InvocationTargetException e) {
|
||||
logger.warning("Test " + displayName(testMethod) + " failed with exception: " + e.getCause().getMessage());
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<red>Test " + displayName(testMethod) + " failed with exception: " + e.getCause().getMessage()));
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
logger.warning("Unexpected exception in test " + fpTest.name() + ": " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
long testEnd = System.currentTimeMillis();
|
||||
logger.info("Test " + displayName(testMethod) + " took " + (testEnd - testStart) + "ms");
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize("<green>Test " + displayName(testMethod) + " took " + (testEnd - testStart) + "ms"));
|
||||
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
logger.warning("Thread interrupted while waiting between tests: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a display name for a given test method, incorporating annotation details if present.
|
||||
*
|
||||
* @param m the method for which to generate the display name
|
||||
* @return a display name that includes the test class and method name, and optionally the value of the FPTest annotation's name attribute if the annotation is present
|
||||
*/
|
||||
public String displayName(Method m) {
|
||||
if (!m.isAnnotationPresent(FPTest.class)) {
|
||||
return testClass.getSimpleName() + "#" + m.getName();
|
||||
}
|
||||
|
||||
FPTest fpTest = m.getAnnotation(FPTest.class);
|
||||
return testClass.getSimpleName() + "#" + m.getName() + " (" + fpTest.name() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation to mark a method that should be executed after each test case in a test class.
|
||||
* This annotation is used to identify methods that perform teardown operations, ensuring
|
||||
* that the test environment is cleaned up and reset after each individual test method is executed.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPAfterEach {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* FPBeforeEach is a custom annotation designed to be used on methods that should be executed before each test method.
|
||||
* Methods annotated with FPBeforeEach are typically used to perform setup operations needed before executing each test case.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPBeforeEach {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancylib.tests.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* FPTest is a custom annotation designed to be used on methods for marking them as test cases.
|
||||
* It helps to identify methods that should be treated as test cases in the testing framework.
|
||||
* The annotation's attributes allow for providing a human-readable test name and an optional flag to skip the test.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface FPTest {
|
||||
|
||||
/**
|
||||
* Specifies the name of the test case. This name is used to identify the test case
|
||||
* in reports, logs, and other contexts where the test case is referenced.
|
||||
*
|
||||
* @return the name of the test case
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Indicates whether the annotated test case should be skipped during test execution.
|
||||
*
|
||||
* @return true if the test case should be skipped, false otherwise
|
||||
*/
|
||||
boolean skip() default false;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.oliver.fancylib.translations;
|
||||
|
||||
import de.oliver.fancylib.translations.message.Message;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Language {
|
||||
|
||||
private final String languageCode;
|
||||
private final String languageName;
|
||||
private final Map<String, Message> messages;
|
||||
|
||||
public Language(String languageCode, String languageName) {
|
||||
this.languageCode = languageCode;
|
||||
this.languageName = languageName;
|
||||
this.messages = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addMessage(String key, Message message) {
|
||||
messages.put(key, message);
|
||||
}
|
||||
|
||||
public Message getMessage(String key) {
|
||||
return messages.getOrDefault(key, null);
|
||||
}
|
||||
|
||||
public String getLanguageCode() {
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
public String getLanguageName() {
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.oliver.fancylib.translations;
|
||||
|
||||
public record TextConfig(
|
||||
String primaryColor,
|
||||
String secondaryColor,
|
||||
String successColor,
|
||||
String warningColor,
|
||||
String errorColor,
|
||||
String prefix
|
||||
) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package de.oliver.fancylib.translations;
|
||||
|
||||
import de.oliver.fancylib.translations.message.Message;
|
||||
import de.oliver.fancylib.translations.message.MultiMessage;
|
||||
import de.oliver.fancylib.translations.message.SimpleMessage;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Translator {
|
||||
|
||||
private final TextConfig textConfig;
|
||||
private final List<Language> languages;
|
||||
private Language selectedLanguage;
|
||||
private Language fallbackLanguage;
|
||||
|
||||
public Translator(TextConfig textConfig) {
|
||||
this.textConfig = textConfig;
|
||||
this.languages = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void loadLanguages(String pluginFolderPath) {
|
||||
languages.clear();
|
||||
selectedLanguage = null;
|
||||
fallbackLanguage = null;
|
||||
|
||||
File langFolder = new File(pluginFolderPath + File.separator + "languages");
|
||||
if (!langFolder.exists()) {
|
||||
if (!langFolder.mkdirs()) {
|
||||
throw new RuntimeException("Could not create languages folder");
|
||||
}
|
||||
}
|
||||
|
||||
File defaultFile = new File(langFolder, "default.yml");
|
||||
try {
|
||||
InputStream defaultStream = getClass().getResourceAsStream("/languages/default.yml");
|
||||
if (defaultStream == null) {
|
||||
throw new RuntimeException("Could not find default language file");
|
||||
}
|
||||
|
||||
// only copy if hash is different
|
||||
Files.copy(defaultStream, defaultFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not copy default language file");
|
||||
}
|
||||
|
||||
File[] langFiles = langFolder.listFiles();
|
||||
if (langFiles == null) {
|
||||
throw new RuntimeException("Could not list language files");
|
||||
}
|
||||
|
||||
for (File langFile : langFiles) {
|
||||
languages.add(loadLanguageFile(langFile));
|
||||
}
|
||||
|
||||
fallbackLanguage = languages.stream()
|
||||
.filter(language -> language.getLanguageCode().equals("default"))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (fallbackLanguage == null) {
|
||||
throw new RuntimeException("Could not find fallback language");
|
||||
}
|
||||
}
|
||||
|
||||
private Language loadLanguageFile(File langFile) {
|
||||
String fileName = langFile.getName();
|
||||
String languageCode = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||
|
||||
YamlConfiguration lang = YamlConfiguration.loadConfiguration(langFile);
|
||||
String languageName = lang.getString("language_name", languageCode);
|
||||
|
||||
Language language = new Language(languageCode, languageName);
|
||||
|
||||
|
||||
ConfigurationSection messages = lang.getConfigurationSection("messages");
|
||||
if (messages == null) {
|
||||
throw new RuntimeException("Language file " + langFile.getName() + " does not contain a messages section");
|
||||
}
|
||||
|
||||
for (String key : messages.getKeys(true)) {
|
||||
if (messages.isString(key)) {
|
||||
SimpleMessage message = new SimpleMessage(textConfig, messages.getString(key));
|
||||
language.addMessage(key, message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (messages.isList(key)) {
|
||||
List<String> list = messages.getStringList(key);
|
||||
language.addMessage(key, new MultiMessage(textConfig, list));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
public Message translate(String key) {
|
||||
Message message = selectedLanguage.getMessage(key);
|
||||
|
||||
if (message == null) {
|
||||
message = fallbackLanguage.getMessage(key);
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
return new SimpleMessage(textConfig, "<red>Missing translation for key <i>" + key);
|
||||
}
|
||||
|
||||
return message.copy();
|
||||
}
|
||||
|
||||
public List<Language> getLanguages() {
|
||||
return languages;
|
||||
}
|
||||
|
||||
public Language getSelectedLanguage() {
|
||||
return selectedLanguage;
|
||||
}
|
||||
|
||||
public Translator setSelectedLanguage(Language selectedLanguage) {
|
||||
this.selectedLanguage = selectedLanguage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Language getFallbackLanguage() {
|
||||
return fallbackLanguage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package de.oliver.fancylib.translations.message;
|
||||
|
||||
import de.oliver.fancylib.translations.TextConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public abstract class Message {
|
||||
|
||||
protected final TextConfig config;
|
||||
protected TagResolver.Builder tagResolverBuilder = TagResolver.builder();
|
||||
|
||||
public Message(TextConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public Message addTagResolver(TagResolver resolver) {
|
||||
tagResolverBuilder = tagResolverBuilder.resolver(resolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void applyColorPlaceholders() {
|
||||
replace("primaryColor", "<color:" + config.primaryColor() + ">");
|
||||
replace("secondaryColor", "<color:" + config.secondaryColor() + ">");
|
||||
replace("successColor", "<color:" + config.successColor() + ">");
|
||||
replace("warningColor", "<color:" + config.warningColor() + ">");
|
||||
replace("errorColor", "<color:" + config.errorColor() + ">");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a placeholder in the message
|
||||
*
|
||||
* @param placeholder the placeholder to replace
|
||||
* @param replacement the replacement
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message replace(String placeholder, String replacement);
|
||||
|
||||
/**
|
||||
* Replaces a placeholder in the message, all known tags are stripped from the replacement
|
||||
*
|
||||
* @param placeholder the placeholder to replace
|
||||
* @param replacement the replacement
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message replaceStripped(String placeholder, String replacement);
|
||||
|
||||
/**
|
||||
* Adds the prefix to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message withPrefix();
|
||||
|
||||
/**
|
||||
* Adds the primary color to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message primary();
|
||||
|
||||
/**
|
||||
* Adds the secondary color to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message secondary();
|
||||
|
||||
/**
|
||||
* Adds the success color to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message success();
|
||||
|
||||
/**
|
||||
* Adds the warning color to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message warning();
|
||||
|
||||
/**
|
||||
* Adds the error color to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message error();
|
||||
|
||||
/**
|
||||
* Applies custom placeholders to the message
|
||||
*
|
||||
* @return this message
|
||||
*/
|
||||
public abstract Message applyCustomPlaceholders();
|
||||
|
||||
/**
|
||||
* Builds the message as a component
|
||||
*
|
||||
* @return the built component
|
||||
*/
|
||||
public abstract Component buildComponent();
|
||||
|
||||
/**
|
||||
* Copies the message
|
||||
*
|
||||
* @return the copied message
|
||||
*/
|
||||
public abstract Message copy();
|
||||
|
||||
public void send(CommandSender receiver) {
|
||||
Component msg = buildComponent();
|
||||
if (Component.empty().equals(msg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
receiver.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void actionbar(Player receiver) {
|
||||
Component msg = buildComponent();
|
||||
if (Component.empty().equals(msg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
receiver.sendActionBar(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package de.oliver.fancylib.translations.message;
|
||||
|
||||
import de.oliver.fancylib.translations.TextConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiMessage extends Message {
|
||||
|
||||
private final List<String> messages;
|
||||
|
||||
public MultiMessage(TextConfig config, List<String> messages) {
|
||||
super(config);
|
||||
this.messages = new ArrayList<>(messages);
|
||||
|
||||
applyColorPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message replace(String placeholder, String replacement) {
|
||||
messages.replaceAll(s -> s
|
||||
.replace("{" + placeholder + "}", replacement)
|
||||
.replace("%" + placeholder + "%", replacement));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message replaceStripped(String placeholder, String replacement) {
|
||||
return replace(placeholder, MiniMessage.miniMessage().stripTags(replacement, tagResolverBuilder.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message withPrefix() {
|
||||
messages.replaceAll(s -> config.prefix() + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message primary() {
|
||||
messages.replaceAll(s -> "<color:" + config.primaryColor() + ">" + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message secondary() {
|
||||
messages.replaceAll(s -> "<color:" + config.secondaryColor() + ">" + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message success() {
|
||||
messages.replaceAll(s -> "<color:" + config.successColor() + ">" + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message warning() {
|
||||
messages.replaceAll(s -> "<color:" + config.warningColor() + ">" + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message error() {
|
||||
messages.replaceAll(s -> "<color:" + config.errorColor() + ">" + s);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message applyCustomPlaceholders() {
|
||||
//TODO: add ChatColorHandler support
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component buildComponent() {
|
||||
String joined = String.join("\n", messages);
|
||||
return MiniMessage.miniMessage().deserialize(joined, tagResolverBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message copy() {
|
||||
return new MultiMessage(config, messages);
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return String.join("\n", messages);
|
||||
}
|
||||
|
||||
public List<String> getRawMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public List<SimpleMessage> getSimpleMessages() {
|
||||
List<SimpleMessage> messages = new ArrayList<>();
|
||||
for (String s : this.messages) {
|
||||
messages.add(new SimpleMessage(config, s));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public MultiMessage page(int page, int messagesPerPage) {
|
||||
List<String> pageMessages = new ArrayList<>();
|
||||
int start = (page - 1) * messagesPerPage;
|
||||
int end = Math.min(start + messagesPerPage, messages.size());
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
pageMessages.add(messages.get(i));
|
||||
}
|
||||
|
||||
return new MultiMessage(config, pageMessages);
|
||||
}
|
||||
|
||||
public int getPages(int messagesPerPage) {
|
||||
return (int) Math.ceil((double) messages.size() / messagesPerPage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package de.oliver.fancylib.translations.message;
|
||||
|
||||
import de.oliver.fancylib.translations.TextConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SimpleMessage extends Message {
|
||||
|
||||
private String message;
|
||||
|
||||
public SimpleMessage(TextConfig config, String message) {
|
||||
super(config);
|
||||
this.message = message;
|
||||
|
||||
applyColorPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage replace(String placeholder, String replacement) {
|
||||
message = message
|
||||
.replace("{" + placeholder + "}", replacement)
|
||||
.replace("%" + placeholder + "%", replacement);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message replaceStripped(String placeholder, String replacement) {
|
||||
return replace(placeholder, MiniMessage.miniMessage().stripTags(replacement, tagResolverBuilder.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage withPrefix() {
|
||||
message = config.prefix() + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage primary() {
|
||||
message = "<color:" + config.primaryColor() + ">" + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage secondary() {
|
||||
message = "<color:" + config.secondaryColor() + ">" + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage success() {
|
||||
message = "<color:" + config.successColor() + ">" + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage warning() {
|
||||
message = "<color:" + config.warningColor() + ">" + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage error() {
|
||||
message = "<color:" + config.errorColor() + ">" + message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleMessage applyCustomPlaceholders() {
|
||||
// TODO: add ChatColorHandler support
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component buildComponent() {
|
||||
return MiniMessage.miniMessage().deserialize(message, tagResolverBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message copy() {
|
||||
return new SimpleMessage(config, message);
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void actionbar(Player receiver) {
|
||||
receiver.sendActionBar(buildComponent());
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package de.oliver.fancylib.versionFetcher;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
public class HangarVersionFetcher implements VersionFetcher{
|
||||
|
||||
private final String pluginName;
|
||||
private ComparableVersion newestVersion;
|
||||
|
||||
public HangarVersionFetcher(String pluginName) {
|
||||
this.pluginName = pluginName;
|
||||
this.newestVersion = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparableVersion fetchNewestVersion() {
|
||||
if(newestVersion != null) return newestVersion;
|
||||
|
||||
String versionStr = VersionFetcher.getDataFromUrl("https://hangar.papermc.io/api/v1/projects/" + pluginName + "/latestrelease");
|
||||
if(versionStr == null || versionStr.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
|
||||
newestVersion = new ComparableVersion(versionStr);
|
||||
return newestVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl() {
|
||||
return "https://hangar.papermc.io/Oliver/" + pluginName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancylib.versionFetcher;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class MasterVersionFetcher implements VersionFetcher{
|
||||
|
||||
private final String pluginName;
|
||||
private ComparableVersion newestVersion;
|
||||
private LinkedList<VersionFetcher> fetchers;
|
||||
|
||||
public MasterVersionFetcher(String pluginName) {
|
||||
this.pluginName = pluginName;
|
||||
this.fetchers = new LinkedList<>();
|
||||
fetchers.push(new ReposiliteVersionFetcher(pluginName));
|
||||
fetchers.push(new ModrinthVersionFetcher(pluginName));
|
||||
fetchers.push(new HangarVersionFetcher(pluginName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparableVersion fetchNewestVersion() {
|
||||
for (VersionFetcher fetcher : fetchers) {
|
||||
ComparableVersion version = fetcher.fetchNewestVersion();
|
||||
if(version == null) continue;
|
||||
newestVersion = version;
|
||||
return newestVersion;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl() {
|
||||
return "https://modrinth.com/plugin/" + pluginName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.oliver.fancylib.versionFetcher;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ModrinthVersionFetcher implements VersionFetcher {
|
||||
|
||||
private final String pluginName;
|
||||
private ComparableVersion newestVersion;
|
||||
|
||||
public ModrinthVersionFetcher(String pluginName) {
|
||||
this.pluginName = pluginName;
|
||||
this.newestVersion = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparableVersion fetchNewestVersion() {
|
||||
if (newestVersion != null) return newestVersion;
|
||||
|
||||
String jsonString = de.oliver.fancylib.versionFetcher.VersionFetcher.getDataFromUrl("https://api.modrinth.com/v2/project/" + pluginName.toLowerCase() + "/version");
|
||||
if (jsonString == null || jsonString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
Map<String, Object>[] versions = gson.fromJson(jsonString, Map[].class);
|
||||
|
||||
|
||||
for (Map<String, Object> version : versions) {
|
||||
if (!version.get("version_type").equals("release")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String versionNumber = (String) version.get("version_number");
|
||||
newestVersion = new ComparableVersion(versionNumber);
|
||||
break;
|
||||
}
|
||||
|
||||
return newestVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl() {
|
||||
return "https://modrinth.com/plugin/" + pluginName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.oliver.fancylib.versionFetcher;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ReposiliteVersionFetcher implements VersionFetcher{
|
||||
|
||||
private final String pluginName;
|
||||
private ComparableVersion newestVersion;
|
||||
|
||||
public ReposiliteVersionFetcher(String pluginName) {
|
||||
this.pluginName = pluginName;
|
||||
this.newestVersion = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparableVersion fetchNewestVersion() {
|
||||
if (newestVersion != null) return newestVersion;
|
||||
|
||||
String jsonString = VersionFetcher.getDataFromUrl("https://repo.fancyplugins.de/api/maven/latest/version/releases/de/oliver/" + pluginName);
|
||||
if (jsonString == null || jsonString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
Map<String, Object> data = gson.fromJson(jsonString, Map.class);
|
||||
String versionStr = (String) data.get("version");
|
||||
|
||||
newestVersion = new ComparableVersion(versionStr);
|
||||
return newestVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl() {
|
||||
return "https://modrinth.com/plugin/" + pluginName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancylib.versionFetcher;
|
||||
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Scanner;
|
||||
|
||||
public interface VersionFetcher {
|
||||
|
||||
ComparableVersion fetchNewestVersion();
|
||||
String getDownloadUrl();
|
||||
|
||||
static String getDataFromUrl(String urlString) {
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
connection.setConnectTimeout(300);
|
||||
Scanner scanner = new Scanner(connection.getInputStream(), StandardCharsets.UTF_8).useDelimiter("\\A");
|
||||
|
||||
return scanner.hasNext() ? scanner.next() : "";
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package de.oliver.fancylib.jdb;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class JDBTest {
|
||||
|
||||
//This class tests the get operation of the JDB class,
|
||||
//which is supposed to retrieve and deserialize a JSON document
|
||||
//from a given path in the file system.
|
||||
|
||||
private final String basePath = "./test_files/";
|
||||
|
||||
public static void cleanUpDirectory(String path) throws IOException {
|
||||
Path directory = Paths.get(path);
|
||||
if (Files.exists(directory)) {
|
||||
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws IOException {
|
||||
cleanUpDirectory(basePath);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() throws IOException {
|
||||
cleanUpDirectory(basePath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetObject() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "test_file";
|
||||
jdb.set(path, "Test message");
|
||||
|
||||
// Act
|
||||
String result = jdb.get(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertEquals("Test message", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetObjectNonExisting() throws IOException {
|
||||
// Prepare
|
||||
JDB jdb = new JDB("./test_files/");
|
||||
String path = "does_not_exist";
|
||||
|
||||
// Act
|
||||
Object result = jdb.get(path, Object.class);
|
||||
|
||||
// Assert
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllObjects() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "test_files";
|
||||
jdb.set(path + "/obj1", "Test message 1");
|
||||
jdb.set(path + "/obj2", "Test message 2");
|
||||
jdb.set(path + "/obj3", "Test message 3");
|
||||
|
||||
// Act
|
||||
List<String> result = jdb.getAll(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertEquals(3, result.size());
|
||||
assertTrue(result.contains("Test message 1"));
|
||||
assertTrue(result.contains("Test message 2"));
|
||||
assertTrue(result.contains("Test message 3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllObjectsNonExisting() throws IOException {
|
||||
// Prepare
|
||||
JDB jdb = new JDB("./test_files/");
|
||||
String path = "does_not_exist";
|
||||
|
||||
// Act
|
||||
List<Object> result = jdb.getAll(path, Object.class);
|
||||
|
||||
// Assert
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNewObject() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "new_object";
|
||||
String value = "New message";
|
||||
|
||||
// Act
|
||||
jdb.set(path, value);
|
||||
String result = jdb.get(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertEquals(value, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetExistingObject() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "existing_object";
|
||||
String value = "Existing message";
|
||||
jdb.set(path, "Old message");
|
||||
|
||||
// Act
|
||||
jdb.set(path, value);
|
||||
String result = jdb.get(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertEquals(value, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetObjectNull() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "null_object";
|
||||
|
||||
// Act
|
||||
jdb.set(path, null);
|
||||
String result = jdb.get(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteWhenFileExists() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "existing_file";
|
||||
String value = "Test message";
|
||||
jdb.set(path, value);
|
||||
|
||||
// Act
|
||||
jdb.delete(path);
|
||||
String result = jdb.get(path, String.class);
|
||||
|
||||
// Assert
|
||||
assertNull(result);
|
||||
|
||||
File file = new File(basePath + path + ".json");
|
||||
assertFalse(file.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteWhenFileNotExists() {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "non_existing_file";
|
||||
|
||||
// Act
|
||||
jdb.delete(path);
|
||||
|
||||
// Assert
|
||||
File file = new File(basePath + path + ".json");
|
||||
assertFalse(file.exists());
|
||||
}
|
||||
|
||||
// The getDocument method in the JDB class is supposed to retrieve and deserialize a JSON document(but encapsulated in a JDocument) from a given path in the file system.
|
||||
// Testing getDocument method when the file exists
|
||||
@Test
|
||||
public void testGetDocumentWhenFileExists() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "existing_file";
|
||||
TestObject value = new TestObject("Test message");
|
||||
jdb.set(path, value);
|
||||
|
||||
// Act
|
||||
JDocument document = jdb.getDocument(path);
|
||||
|
||||
// Assert
|
||||
assertNotNull(document);
|
||||
assertEquals(value.message(), document.getString("message"));
|
||||
}
|
||||
|
||||
// Testing the getDocument method when the file does not exist
|
||||
@Test
|
||||
public void testGetDocumentWhenFileDoesNotExist() throws IOException {
|
||||
// Prepare
|
||||
String basePath = "./test_files/";
|
||||
JDB jdb = new JDB(basePath);
|
||||
String path = "non_existing_file";
|
||||
|
||||
// Act
|
||||
JDocument document = jdb.getDocument(path);
|
||||
|
||||
// Assert
|
||||
assertNull(document);
|
||||
}
|
||||
|
||||
record TestObject(String message) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
package de.oliver.fancylib.jdb;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class JDocumentTest {
|
||||
|
||||
/**
|
||||
* The JDocumentTest class contains unit tests for the JDocument class.
|
||||
* The get method in the JDocument class is being tested here.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGet_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", "value1");
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
Object result = jDocument.get("key1");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("value1", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
Object result = jDocument.get("key1");
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
Object result = jDocument.get("key1.key2");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("value2", result.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
Object result = jDocument.get("key1.key3");
|
||||
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The contains method in the JDocument class is being tested here.
|
||||
* It checks whether a given key is present in the JDocument's data or not.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testContains_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", "value1");
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.contains("key1");
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
boolean result = jDocument.contains("key1");
|
||||
|
||||
assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.contains("key1.key2");
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.contains("key1.key3");
|
||||
|
||||
assertFalse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getKeys method in the JDocument class is being tested here.
|
||||
* It retrieves the keys of the nested Map present within the data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetKeys_Success_SingleKey() {
|
||||
Map<String, Object> innerData = new HashMap<>();
|
||||
innerData.put("innerKey1", "value1");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", innerData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
Set<String> keys = jDocument.getKeys("key1");
|
||||
|
||||
assertNotNull(keys);
|
||||
assertEquals(1, keys.size());
|
||||
assertTrue(keys.contains("innerKey1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKeys_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
Set<String> keys = jDocument.getKeys("key1");
|
||||
|
||||
assertNotNull(keys);
|
||||
assertTrue(keys.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKeys_Success_MultipleKeys() {
|
||||
Map<String, Object> innerData = new HashMap<>();
|
||||
innerData.put("innerKey1", "value1");
|
||||
innerData.put("innerKey2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", innerData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
Set<String> keys = jDocument.getKeys("key1");
|
||||
|
||||
assertNotNull(keys);
|
||||
assertEquals(2, keys.size());
|
||||
assertTrue(keys.contains("innerKey1"));
|
||||
assertTrue(keys.contains("innerKey2"));
|
||||
}
|
||||
|
||||
/**
|
||||
* The getString method in the JDocument class is being tested here.
|
||||
* It returns a String value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetString_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", "value1");
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
String result = jDocument.getString("key1");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("value1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetString_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
String result = jDocument.getString("key1");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetString_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
String result = jDocument.getString("key1.key2");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("value2", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetString_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", "value2");
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
String result = jDocument.getString("key1.key3");
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getBoolean method in the JDocument class is being tested here.
|
||||
* It retrieves a boolean value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetBoolean_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", true);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.getBoolean("key1");
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBoolean_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
boolean result = jDocument.getBoolean("key1");
|
||||
|
||||
assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBoolean_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", true);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.getBoolean("key1.key2");
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBoolean_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", true);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
boolean result = jDocument.getBoolean("key1.key3");
|
||||
|
||||
assertFalse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getByte method in the JDocument class is being tested here.
|
||||
* It retrieves a byte value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetByte_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", (byte) 1);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
byte result = jDocument.getByte("key1");
|
||||
|
||||
assertEquals((byte) 1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByte_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
byte result = jDocument.getByte("key1");
|
||||
|
||||
assertEquals((byte) 0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByte_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", (byte) 2);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
byte result = jDocument.getByte("key1.key2");
|
||||
|
||||
assertEquals((byte) 2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByte_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", (byte) 2);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
byte result = jDocument.getByte("key1.key3");
|
||||
|
||||
assertEquals((byte) 0, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getShort method in the JDocument class is being tested here.
|
||||
* It retrieves a short value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetShort_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", (short) 1);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
short result = jDocument.getShort("key1");
|
||||
|
||||
assertEquals((short) 1, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShort_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
short result = jDocument.getShort("key1");
|
||||
|
||||
assertEquals((short) 0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShort_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", (short) 2);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
short result = jDocument.getShort("key1.key2");
|
||||
|
||||
assertEquals((short) 2, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetShort_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", (short) 2);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
short result = jDocument.getShort("key1.key3");
|
||||
|
||||
assertEquals((short) 0, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getInt method in the JDocument class is being tested here.
|
||||
* It retrieves an integer value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetInt_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", 123);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
int result = jDocument.getInt("key1");
|
||||
|
||||
assertEquals(123, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInt_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
int result = jDocument.getInt("key1");
|
||||
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInt_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 456);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
int result = jDocument.getInt("key1.key2");
|
||||
|
||||
assertEquals(456, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInt_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 456);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
int result = jDocument.getInt("key1.key3");
|
||||
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getLong method in the JDocument class is being tested here.
|
||||
* It retrieves a long value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetLong_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", 123L);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
long result = jDocument.getLong("key1");
|
||||
|
||||
assertEquals(123L, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLong_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
long result = jDocument.getLong("key1");
|
||||
|
||||
assertEquals(0L, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLong_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 456L);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
long result = jDocument.getLong("key1.key2");
|
||||
|
||||
assertEquals(456L, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLong_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 456L);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
long result = jDocument.getLong("key1.key3");
|
||||
|
||||
assertEquals(0L, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getFloat method in the JDocument class is being tested here.
|
||||
* It retrieves a float value of the specified key from the JDocument's data.
|
||||
*/
|
||||
@Test
|
||||
public void testGetFloat_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", 1.23f);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
float result = jDocument.getFloat("key1");
|
||||
|
||||
assertEquals(1.23f, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFloat_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
float result = jDocument.getFloat("key1");
|
||||
|
||||
assertEquals(0f, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFloat_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 4.56f);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
float result = jDocument.getFloat("key1.key2");
|
||||
|
||||
assertEquals(4.56f, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFloat_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 4.56f);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
float result = jDocument.getFloat("key1.key3");
|
||||
|
||||
assertEquals(0f, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getDouble method in the JDocument class is being tested here.
|
||||
* It retrieves a double value of the specified key from the JDocument's data.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testGetDouble_Success_SingleKey() {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", 1.23d);
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
double result = jDocument.getDouble("key1");
|
||||
|
||||
assertEquals(1.23d, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDouble_Failure_KeyNotFound() {
|
||||
JDocument jDocument = new JDocument(Collections.emptyMap());
|
||||
|
||||
double result = jDocument.getDouble("key1");
|
||||
|
||||
assertEquals(0d, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDouble_Success_NestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 4.56d);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
double result = jDocument.getDouble("key1.key2");
|
||||
|
||||
assertEquals(4.56d, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDouble_Failure_NonExistentNestedKey() {
|
||||
Map<String, Object> nestedData = new HashMap<>();
|
||||
nestedData.put("key2", 4.56d);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("key1", nestedData);
|
||||
|
||||
JDocument jDocument = new JDocument(data);
|
||||
|
||||
double result = jDocument.getDouble("key1.key3");
|
||||
|
||||
assertEquals(0d, result);
|
||||
}
|
||||
}
|
||||
46
libraries/packets/.gitignore
vendored
Normal file
46
libraries/packets/.gitignore
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
## run paper
|
||||
**/run/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
58
libraries/packets/README.md
Normal file
58
libraries/packets/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||

|
||||
|
||||
## Using Minecraft internals made easier.
|
||||
|
||||
Initially developed for FancyNpcs and FancyHolograms, FancySitula is a library that simplifies the process of
|
||||
interacting with Minecraft internals. It provides a simple and easy to use API to interact with Minecraft packets and
|
||||
entities.
|
||||
|
||||
## Features
|
||||
|
||||
- Easy to use API for creating and sending packets
|
||||
- Powerful factory classes for creating packets
|
||||
- Wrapper classes for Minecraft packets and entities
|
||||
- Support for multiple Minecraft versions
|
||||
- No third-party dependencies and works out of the box
|
||||
|
||||
## Supported packets
|
||||
|
||||
The following packets are currently supported:
|
||||
|
||||
- ClientboundAddEntityPacket
|
||||
- ClientboundPlayerInfoRemovePacket
|
||||
- ClientboundPlayerInfoUpdatePacket
|
||||
- ClientboundRemoveEntitiesPacket
|
||||
- ClientboundRotateHeadPacket
|
||||
- ClientboundSetEntityDataPacket
|
||||
- ClientboundSetEquipmentPacket
|
||||
- ClientboundTeleportEntityPacket
|
||||
|
||||
More packets will be added when needed / requested (contributions are welcome).
|
||||
|
||||
## Supported Minecraft versions
|
||||
|
||||
FancySitula will support the latest Minecraft version and additional older versions. The following versions are
|
||||
supported:
|
||||
|
||||
- [x] 1.21.1
|
||||
- [x] 1.21
|
||||
- [x] 1.20.6
|
||||
- [x] 1.20.5
|
||||
- [ ] 1.20.4
|
||||
- [ ] 1.20.2
|
||||
- [ ] 1.20.1
|
||||
|
||||
## Missing Packets for FancyNpcs
|
||||
|
||||
- [x] ClientboundPlayerInfoUpdatePacket
|
||||
- [x] ClientboundAddEntityPacket
|
||||
- [x] ClientboundPlayerInfoRemovePacket
|
||||
- [x] ClientboundRemoveEntitiesPacket
|
||||
- [x] ClientboundTeleportEntityPacket
|
||||
- [x] ClientboundRotateHeadPacket
|
||||
- [x] ClientboundSetEquipmentPacket
|
||||
- [x] ClientboundSetEntityDataPacket
|
||||
- [x] ClientboundSetPlayerTeamPacket
|
||||
- [ ] ClientboundUpdateAttributesPacket
|
||||
- [ ] ClientboundAnimatePacket
|
||||
- [ ] ClientboundSetPassengersPacket
|
||||
25
libraries/packets/api/build.gradle.kts
Normal file
25
libraries/packets/api/build.gradle.kts
Normal file
@@ -0,0 +1,25 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||
compileOnly("de.oliver.FancyAnalytics:logger:0.0.4")
|
||||
}
|
||||
|
||||
tasks {
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 21
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.oliver.fancysitula.api;
|
||||
|
||||
import de.oliver.fancyanalytics.logger.ExtendedFancyLogger;
|
||||
|
||||
public interface IFancySitula {
|
||||
ExtendedFancyLogger LOGGER = new ExtendedFancyLogger("FancySitula");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
import de.oliver.fancysitula.api.utils.entityData.FS_BlockDisplayData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FS_BlockDisplay extends FS_Display {
|
||||
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData blockData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_BlockDisplayData.BLOCK, null);
|
||||
|
||||
public FS_BlockDisplay() {
|
||||
super(EntityType.BLOCK_DISPLAY);
|
||||
}
|
||||
|
||||
public org.bukkit.block.BlockState getBlock() {
|
||||
return (org.bukkit.block.BlockState) this.blockData.getValue();
|
||||
}
|
||||
|
||||
public void setBlock(org.bukkit.block.BlockState block) {
|
||||
this.blockData.setValue(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FS_ClientboundSetEntityDataPacket.EntityData> getEntityData() {
|
||||
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = super.getEntityData();
|
||||
entityData.add(this.blockData);
|
||||
return entityData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
import de.oliver.fancysitula.api.utils.entityData.FS_DisplayData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FS_Display extends FS_Entity {
|
||||
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData transformationInterpolationStartDeltaTicksData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData transformationInterpolationDurationData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.TRANSFORMATION_INTERPOLATION_DURATION, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData posRotInterpolationDurationData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.POS_ROT_INTERPOLATION_DURATION, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData translationData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.TRANSLATION, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData scaleData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.SCALE, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData leftRotationData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.LEFT_ROTATION, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData rightRotationData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.RIGHT_ROTATION, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData billboardRenderConstraintsData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.BILLBOARD_RENDER_CONSTRAINTS, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData brightnessOverrideData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.BRIGHTNESS_OVERRIDE, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData viewRangeData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.VIEW_RANGE, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData shadowRadiusData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.SHADOW_RADIUS, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData shadowStrengthData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.SHADOW_STRENGTH, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData widthData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.WIDTH, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData heightData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.HEIGHT, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData glowColorOverrideData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_DisplayData.GLOW_COLOR_OVERRIDE, null);
|
||||
|
||||
public FS_Display(EntityType type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public int getTransformationInterpolationStartDeltaTicks() {
|
||||
return (int) this.transformationInterpolationStartDeltaTicksData.getValue();
|
||||
}
|
||||
|
||||
public void setTransformationInterpolationStartDeltaTicks(int transformationInterpolationStartDeltaTicks) {
|
||||
this.transformationInterpolationStartDeltaTicksData.setValue(transformationInterpolationStartDeltaTicks);
|
||||
}
|
||||
|
||||
public int getTransformationInterpolationDuration() {
|
||||
return (int) this.transformationInterpolationDurationData.getValue();
|
||||
}
|
||||
|
||||
public void setTransformationInterpolationDuration(int transformationInterpolationDuration) {
|
||||
this.transformationInterpolationDurationData.setValue(transformationInterpolationDuration);
|
||||
}
|
||||
|
||||
public int getPosRotInterpolationDuration() {
|
||||
return (int) this.posRotInterpolationDurationData.getValue();
|
||||
}
|
||||
|
||||
public void setPosRotInterpolationDuration(int posRotInterpolationDuration) {
|
||||
this.posRotInterpolationDurationData.setValue(posRotInterpolationDuration);
|
||||
}
|
||||
|
||||
public org.joml.Vector3f getTranslation() {
|
||||
return (org.joml.Vector3f) this.translationData.getValue();
|
||||
}
|
||||
|
||||
public void setTranslation(org.joml.Vector3f translation) {
|
||||
this.translationData.setValue(translation);
|
||||
}
|
||||
|
||||
public org.joml.Vector3f getScale() {
|
||||
return (org.joml.Vector3f) this.scaleData.getValue();
|
||||
}
|
||||
|
||||
public void setScale(org.joml.Vector3f scale) {
|
||||
this.scaleData.setValue(scale);
|
||||
}
|
||||
|
||||
public org.joml.Quaternionf getLeftRotation() {
|
||||
return (org.joml.Quaternionf) this.leftRotationData.getValue();
|
||||
}
|
||||
|
||||
public void setLeftRotation(org.joml.Quaternionf leftRotation) {
|
||||
this.leftRotationData.setValue(leftRotation);
|
||||
}
|
||||
|
||||
public org.joml.Quaternionf getRightRotation() {
|
||||
return (org.joml.Quaternionf) this.rightRotationData.getValue();
|
||||
}
|
||||
|
||||
public void setRightRotation(org.joml.Quaternionf rightRotation) {
|
||||
this.rightRotationData.setValue(rightRotation);
|
||||
}
|
||||
|
||||
public byte getBillboardRenderConstraints() {
|
||||
return (byte) this.billboardRenderConstraintsData.getValue();
|
||||
}
|
||||
|
||||
public void setBillboardRenderConstraints(byte billboardRenderConstraints) {
|
||||
this.billboardRenderConstraintsData.setValue(billboardRenderConstraints);
|
||||
}
|
||||
|
||||
public Billboard getBillboard() {
|
||||
return Billboard.getById(getBillboardRenderConstraints());
|
||||
}
|
||||
|
||||
public void setBillboard(Billboard billboard) {
|
||||
this.billboardRenderConstraintsData.setValue(billboard.getId());
|
||||
}
|
||||
|
||||
public int getBrightnessOverride() {
|
||||
return (int) this.brightnessOverrideData.getValue();
|
||||
}
|
||||
|
||||
public void setBrightnessOverride(int brightnessOverride) {
|
||||
this.brightnessOverrideData.setValue(brightnessOverride);
|
||||
}
|
||||
|
||||
public float getViewRange() {
|
||||
return (float) this.viewRangeData.getValue();
|
||||
}
|
||||
|
||||
public void setViewRange(float viewRange) {
|
||||
this.viewRangeData.setValue(viewRange);
|
||||
}
|
||||
|
||||
public float getShadowRadius() {
|
||||
return (float) this.shadowRadiusData.getValue();
|
||||
}
|
||||
|
||||
public void setShadowRadius(float shadowRadius) {
|
||||
this.shadowRadiusData.setValue(shadowRadius);
|
||||
}
|
||||
|
||||
public float getShadowStrength() {
|
||||
return (float) this.shadowStrengthData.getValue();
|
||||
}
|
||||
|
||||
public void setShadowStrength(float shadowStrength) {
|
||||
this.shadowStrengthData.setValue(shadowStrength);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return (int) this.widthData.getValue();
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.widthData.setValue(width);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return (int) this.heightData.getValue();
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.heightData.setValue(height);
|
||||
}
|
||||
|
||||
public int getGlowColorOverride() {
|
||||
return (int) this.glowColorOverrideData.getValue();
|
||||
}
|
||||
|
||||
public void setGlowColorOverride(int glowColorOverride) {
|
||||
this.glowColorOverrideData.setValue(glowColorOverride);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FS_ClientboundSetEntityDataPacket.EntityData> getEntityData() {
|
||||
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = super.getEntityData();
|
||||
|
||||
entityData.add(this.transformationInterpolationStartDeltaTicksData);
|
||||
entityData.add(this.transformationInterpolationDurationData);
|
||||
entityData.add(this.posRotInterpolationDurationData);
|
||||
entityData.add(this.translationData);
|
||||
entityData.add(this.scaleData);
|
||||
entityData.add(this.leftRotationData);
|
||||
entityData.add(this.rightRotationData);
|
||||
entityData.add(this.billboardRenderConstraintsData);
|
||||
entityData.add(this.brightnessOverrideData);
|
||||
entityData.add(this.viewRangeData);
|
||||
entityData.add(this.shadowRadiusData);
|
||||
entityData.add(this.shadowStrengthData);
|
||||
entityData.add(this.widthData);
|
||||
entityData.add(this.heightData);
|
||||
entityData.add(this.glowColorOverrideData);
|
||||
return entityData;
|
||||
}
|
||||
|
||||
public enum Billboard {
|
||||
FIXED((byte) 0, "fixed"),
|
||||
VERTICAL((byte) 1, "vertical"),
|
||||
HORIZONTAL((byte) 2, "horizontal"),
|
||||
CENTER((byte) 3, "center"),
|
||||
;
|
||||
|
||||
private final byte id;
|
||||
private final String name;
|
||||
|
||||
Billboard(byte id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Billboard getById(byte id) {
|
||||
for (Billboard value : values()) {
|
||||
if (value.getId() == id) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
import de.oliver.fancysitula.api.utils.entityData.FS_EntityData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FS_Entity {
|
||||
|
||||
private static int entityCount = Integer.MAX_VALUE / 2;
|
||||
|
||||
protected int id = entityCount++;
|
||||
protected UUID uuid = UUID.randomUUID();
|
||||
protected EntityType type;
|
||||
|
||||
protected double x = 0;
|
||||
protected double y = 0;
|
||||
protected double z = 0;
|
||||
|
||||
protected float yaw = 0;
|
||||
protected float pitch = 0;
|
||||
protected float headYaw = 0;
|
||||
|
||||
protected int velocityX = 0;
|
||||
protected int velocityY = 0;
|
||||
protected int velocityZ = 0;
|
||||
|
||||
protected int data = 0;
|
||||
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData sharedFlagsData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.SHARED_FLAGS, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData airSupplyData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.AIR_SUPPLY, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData customNameData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.CUSTOM_NAME, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData customNameVisibleData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.CUSTOM_NAME_VISIBLE, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData silentData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.SILENT, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData noGravityData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.NO_GRAVITY, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData ticksFrozenData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_EntityData.TICKS_FROZEN, null);
|
||||
|
||||
public FS_Entity(EntityType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
// Entity data
|
||||
|
||||
public byte getSharedFlags() {
|
||||
return (byte) sharedFlagsData.getValue();
|
||||
}
|
||||
|
||||
public void setSharedFlags(byte sharedFlags) {
|
||||
this.sharedFlagsData.setValue(sharedFlags);
|
||||
}
|
||||
|
||||
public byte getAirSupply() {
|
||||
return (byte) airSupplyData.getValue();
|
||||
}
|
||||
|
||||
public void setAirSupply(byte airSupply) {
|
||||
this.airSupplyData.setValue(airSupply);
|
||||
}
|
||||
|
||||
public Optional<Component> getCustomName() {
|
||||
return (Optional<Component>) customNameData.getValue();
|
||||
}
|
||||
|
||||
public void setCustomName(Optional<Component> customName) {
|
||||
this.customNameData.setValue(customName);
|
||||
}
|
||||
|
||||
public boolean getCustomNameVisible() {
|
||||
return (boolean) customNameVisibleData.getValue();
|
||||
}
|
||||
|
||||
public void setCustomNameVisible(boolean customNameVisible) {
|
||||
this.customNameVisibleData.setValue(customNameVisible);
|
||||
}
|
||||
|
||||
public boolean getSilent() {
|
||||
return (boolean) silentData.getValue();
|
||||
}
|
||||
|
||||
public void setSilent(boolean silent) {
|
||||
this.silentData.setValue(silent);
|
||||
}
|
||||
|
||||
public boolean getNoGravity() {
|
||||
return (boolean) noGravityData.getValue();
|
||||
}
|
||||
|
||||
public void setNoGravity(boolean noGravity) {
|
||||
this.noGravityData.setValue(noGravity);
|
||||
}
|
||||
|
||||
public int getTicksFrozen() {
|
||||
return (int) ticksFrozenData.getValue();
|
||||
}
|
||||
|
||||
public void setTicksFrozen(int ticksFrozen) {
|
||||
this.ticksFrozenData.setValue(ticksFrozen);
|
||||
}
|
||||
|
||||
public List<FS_ClientboundSetEntityDataPacket.EntityData> getEntityData() {
|
||||
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = new ArrayList<>();
|
||||
|
||||
entityData.add(this.sharedFlagsData);
|
||||
entityData.add(this.airSupplyData);
|
||||
entityData.add(this.customNameData);
|
||||
entityData.add(this.customNameVisibleData);
|
||||
entityData.add(this.silentData);
|
||||
entityData.add(this.noGravityData);
|
||||
entityData.add(this.ticksFrozenData);
|
||||
return entityData;
|
||||
}
|
||||
|
||||
// Getter and Setter for all fields
|
||||
|
||||
public void setLocation(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
setLocation(location.getX(), location.getY(), location.getZ());
|
||||
setRotation(location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
public void setRotation(float yaw, float pitch) {
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public void setVelocity(int velocityX, int velocityY, int velocityZ) {
|
||||
this.velocityX = velocityX;
|
||||
this.velocityY = velocityY;
|
||||
this.velocityZ = velocityZ;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(EntityType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public float getHeadYaw() {
|
||||
return headYaw;
|
||||
}
|
||||
|
||||
public void setHeadYaw(float headYaw) {
|
||||
this.headYaw = headYaw;
|
||||
}
|
||||
|
||||
public int getVelocityX() {
|
||||
return velocityX;
|
||||
}
|
||||
|
||||
public void setVelocityX(int velocityX) {
|
||||
this.velocityX = velocityX;
|
||||
}
|
||||
|
||||
public int getVelocityY() {
|
||||
return velocityY;
|
||||
}
|
||||
|
||||
public void setVelocityY(int velocityY) {
|
||||
this.velocityY = velocityY;
|
||||
}
|
||||
|
||||
public int getVelocityZ() {
|
||||
return velocityZ;
|
||||
}
|
||||
|
||||
public void setVelocityZ(int velocityZ) {
|
||||
this.velocityZ = velocityZ;
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
import de.oliver.fancysitula.api.utils.entityData.FS_ItemDisplayData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FS_ItemDisplay extends FS_Display {
|
||||
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData itemData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_ItemDisplayData.ITEM, null);
|
||||
|
||||
public FS_ItemDisplay() {
|
||||
super(EntityType.ITEM_DISPLAY);
|
||||
}
|
||||
|
||||
public org.bukkit.inventory.ItemStack getItem() {
|
||||
return (org.bukkit.inventory.ItemStack) this.itemData.getValue();
|
||||
}
|
||||
|
||||
public void setItem(org.bukkit.inventory.ItemStack item) {
|
||||
this.itemData.setValue(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FS_ClientboundSetEntityDataPacket.EntityData> getEntityData() {
|
||||
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = super.getEntityData();
|
||||
entityData.add(this.itemData);
|
||||
return entityData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class FS_Player extends FS_Entity {
|
||||
|
||||
protected Map<FS_EquipmentSlot, ItemStack> equipment;
|
||||
|
||||
public FS_Player() {
|
||||
super(EntityType.PLAYER);
|
||||
|
||||
this.equipment = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public Map<FS_EquipmentSlot, ItemStack> getEquipment() {
|
||||
return equipment;
|
||||
}
|
||||
|
||||
public void setEquipment(Map<FS_EquipmentSlot, ItemStack> equipment) {
|
||||
this.equipment = equipment;
|
||||
}
|
||||
|
||||
public void setEquipment(FS_EquipmentSlot slot, ItemStack item) {
|
||||
this.equipment.put(slot, item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundPacket;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a real player
|
||||
*/
|
||||
public class FS_RealPlayer {
|
||||
|
||||
@NotNull
|
||||
private final Player bukkitPlayer;
|
||||
|
||||
/**
|
||||
* Creates a new FS_RealPlayer instance
|
||||
* Must have a real bukkit player instance
|
||||
* Used for sending packets to the player
|
||||
*
|
||||
* @param bukkitPlayer the bukkit player instance
|
||||
*/
|
||||
public FS_RealPlayer(@NotNull Player bukkitPlayer) {
|
||||
this.bukkitPlayer = bukkitPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the player
|
||||
* Must have a real bukkit player instance
|
||||
*
|
||||
* @param packet the packet to send
|
||||
*/
|
||||
public void sendPacket(FS_ClientboundPacket packet) {
|
||||
packet.send(this);
|
||||
}
|
||||
|
||||
public @NotNull Player getBukkitPlayer() {
|
||||
return bukkitPlayer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package de.oliver.fancysitula.api.entities;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
import de.oliver.fancysitula.api.utils.entityData.FS_TextDisplayData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FS_TextDisplay extends FS_Display {
|
||||
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData textData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_TextDisplayData.TEXT, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData lineWidthData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_TextDisplayData.LINE_WIDTH, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData backgroundData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_TextDisplayData.BACKGROUND, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData textOpacityData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_TextDisplayData.TEXT_OPACITY, null);
|
||||
protected FS_ClientboundSetEntityDataPacket.EntityData styleFlagsData = new FS_ClientboundSetEntityDataPacket.EntityData(FS_TextDisplayData.STYLE_FLAGS, null);
|
||||
|
||||
public FS_TextDisplay() {
|
||||
super(EntityType.TEXT_DISPLAY);
|
||||
}
|
||||
|
||||
public Component getText() {
|
||||
return (Component) this.textData.getValue();
|
||||
}
|
||||
|
||||
public void setText(Component text) {
|
||||
this.textData.setValue(text);
|
||||
}
|
||||
|
||||
public int getLineWidth() {
|
||||
return (int) this.lineWidthData.getValue();
|
||||
}
|
||||
|
||||
public void setLineWidth(int lineWidth) {
|
||||
this.lineWidthData.setValue(lineWidth);
|
||||
}
|
||||
|
||||
public int getBackground() {
|
||||
return (int) this.backgroundData.getValue();
|
||||
}
|
||||
|
||||
public void setBackground(int background) {
|
||||
this.backgroundData.setValue(background);
|
||||
}
|
||||
|
||||
public byte getTextOpacity() {
|
||||
return (byte) this.textOpacityData.getValue();
|
||||
}
|
||||
|
||||
public void setTextOpacity(byte textOpacity) {
|
||||
this.textOpacityData.setValue(textOpacity);
|
||||
}
|
||||
|
||||
public byte getStyleFlags() {
|
||||
return (byte) this.styleFlagsData.getValue();
|
||||
}
|
||||
|
||||
public void setStyleFlags(byte styleFlags) {
|
||||
this.styleFlagsData.setValue(styleFlags);
|
||||
}
|
||||
|
||||
public void setStyleFlag(byte flag, boolean value) {
|
||||
byte styleFlags = getStyleFlags();
|
||||
if (value) {
|
||||
this.styleFlagsData.setValue((byte) (styleFlags | flag));
|
||||
} else {
|
||||
this.styleFlagsData.setValue((byte) (styleFlags & ~flag));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasStyleFlag(byte flag) {
|
||||
return (getStyleFlags() & flag) == flag;
|
||||
}
|
||||
|
||||
public void setShadow(boolean shadow) {
|
||||
setStyleFlag((byte) 1, shadow);
|
||||
}
|
||||
|
||||
public boolean hasShadow() {
|
||||
return hasStyleFlag((byte) 1);
|
||||
}
|
||||
|
||||
public boolean isSeeThrough() {
|
||||
return hasStyleFlag((byte) 2);
|
||||
}
|
||||
|
||||
public void setSeeThrough(boolean seeThrough) {
|
||||
setStyleFlag((byte) 2, seeThrough);
|
||||
}
|
||||
|
||||
public void setUseDefaultBackground(boolean defaultBackground) {
|
||||
setStyleFlag((byte) 4, defaultBackground);
|
||||
}
|
||||
|
||||
public boolean isUsingDefaultBackground() {
|
||||
return hasStyleFlag((byte) 4);
|
||||
}
|
||||
|
||||
public boolean isAlignLeft() {
|
||||
return hasStyleFlag((byte) 8);
|
||||
}
|
||||
|
||||
public void setAlignLeft(boolean alignLeft) {
|
||||
setStyleFlag((byte) 8, alignLeft);
|
||||
}
|
||||
|
||||
public void setAlignRight(boolean alignRight) {
|
||||
setStyleFlag((byte) 16, alignRight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FS_ClientboundSetEntityDataPacket.EntityData> getEntityData() {
|
||||
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = super.getEntityData();
|
||||
|
||||
entityData.add(this.textData);
|
||||
entityData.add(this.lineWidthData);
|
||||
entityData.add(this.backgroundData);
|
||||
entityData.add(this.textOpacityData);
|
||||
entityData.add(this.styleFlagsData);
|
||||
return entityData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to add an entity to the client's world.
|
||||
*/
|
||||
public abstract class FS_ClientboundAddEntityPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected UUID entityUUID;
|
||||
protected EntityType entityType;
|
||||
|
||||
protected double x;
|
||||
protected double y;
|
||||
protected double z;
|
||||
|
||||
protected float yaw;
|
||||
protected float pitch;
|
||||
protected float headYaw;
|
||||
|
||||
protected int velocityX;
|
||||
protected int velocityY;
|
||||
protected int velocityZ;
|
||||
|
||||
protected int data;
|
||||
|
||||
/**
|
||||
* @param pitch in degrees (0 - 360)
|
||||
* @param headYaw in degrees (0 - 360)
|
||||
*/
|
||||
public FS_ClientboundAddEntityPacket(
|
||||
int entityId,
|
||||
UUID entityUUID,
|
||||
EntityType entityType,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
float headYaw,
|
||||
int velocityX,
|
||||
int velocityY,
|
||||
int velocityZ,
|
||||
int data) {
|
||||
this.entityId = entityId;
|
||||
this.entityUUID = entityUUID;
|
||||
this.entityType = entityType;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.headYaw = headYaw;
|
||||
this.velocityX = velocityX;
|
||||
this.velocityY = velocityY;
|
||||
this.velocityZ = velocityZ;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public UUID getEntityUUID() {
|
||||
return entityUUID;
|
||||
}
|
||||
|
||||
public void setEntityUUID(UUID entityUUID) {
|
||||
this.entityUUID = entityUUID;
|
||||
}
|
||||
|
||||
public EntityType getEntityType() {
|
||||
return entityType;
|
||||
}
|
||||
|
||||
public void setEntityType(EntityType entityType) {
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public float getHeadYaw() {
|
||||
return headYaw;
|
||||
}
|
||||
|
||||
public void setHeadYaw(float headYaw) {
|
||||
this.headYaw = headYaw;
|
||||
}
|
||||
|
||||
public int getVelocityX() {
|
||||
return velocityX;
|
||||
}
|
||||
|
||||
public void setVelocityX(int velocityX) {
|
||||
this.velocityX = velocityX;
|
||||
}
|
||||
|
||||
public int getVelocityY() {
|
||||
return velocityY;
|
||||
}
|
||||
|
||||
public void setVelocityY(int velocityY) {
|
||||
this.velocityY = velocityY;
|
||||
}
|
||||
|
||||
public int getVelocityZ() {
|
||||
return velocityZ;
|
||||
}
|
||||
|
||||
public void setVelocityZ(int velocityZ) {
|
||||
this.velocityZ = velocityZ;
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import de.oliver.fancysitula.api.teams.FS_CollisionRule;
|
||||
import de.oliver.fancysitula.api.teams.FS_NameTagVisibility;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FS_ClientboundCreateOrUpdateTeamPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected Method method;
|
||||
protected String teamName;
|
||||
|
||||
protected CreateTeam createTeam;
|
||||
protected RemoveTeam removeTeam;
|
||||
protected UpdateTeam updateTeam;
|
||||
protected AddEntity addEntity;
|
||||
protected RemoveEntity removeEntity;
|
||||
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket(String teamName, CreateTeam createTeam) {
|
||||
this.method = Method.CREATE_TEAM;
|
||||
this.teamName = teamName;
|
||||
this.createTeam = createTeam;
|
||||
}
|
||||
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket(String teamName, RemoveTeam removeTeam) {
|
||||
this.method = Method.REMOVE_TEAM;
|
||||
this.teamName = teamName;
|
||||
this.removeTeam = removeTeam;
|
||||
}
|
||||
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket(String teamName, UpdateTeam updateTeam) {
|
||||
this.method = Method.UPDATE_TEAM;
|
||||
this.teamName = teamName;
|
||||
this.updateTeam = updateTeam;
|
||||
}
|
||||
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket(String teamName, AddEntity addEntity) {
|
||||
this.method = Method.ADD_ENTITY;
|
||||
this.teamName = teamName;
|
||||
this.addEntity = addEntity;
|
||||
}
|
||||
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket(String teamName, RemoveEntity removeEntity) {
|
||||
this.method = Method.REMOVE_ENTITY;
|
||||
this.teamName = teamName;
|
||||
this.removeEntity = removeEntity;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getTeamName() {
|
||||
return teamName;
|
||||
}
|
||||
|
||||
public void setTeamName(String teamName) {
|
||||
this.teamName = teamName;
|
||||
}
|
||||
|
||||
public CreateTeam getCreateTeam() {
|
||||
return createTeam;
|
||||
}
|
||||
|
||||
public void setCreateTeam(CreateTeam createTeam) {
|
||||
this.createTeam = createTeam;
|
||||
}
|
||||
|
||||
public UpdateTeam getUpdateTeam() {
|
||||
return updateTeam;
|
||||
}
|
||||
|
||||
public void setUpdateTeam(UpdateTeam updateTeam) {
|
||||
this.updateTeam = updateTeam;
|
||||
}
|
||||
|
||||
public AddEntity getAddEntity() {
|
||||
return addEntity;
|
||||
}
|
||||
|
||||
public void setAddEntity(AddEntity addEntity) {
|
||||
this.addEntity = addEntity;
|
||||
}
|
||||
|
||||
public RemoveEntity getRemoveEntity() {
|
||||
return removeEntity;
|
||||
}
|
||||
|
||||
public void setRemoveEntity(RemoveEntity removeEntity) {
|
||||
this.removeEntity = removeEntity;
|
||||
}
|
||||
|
||||
public enum Method {
|
||||
CREATE_TEAM,
|
||||
REMOVE_TEAM,
|
||||
UPDATE_TEAM,
|
||||
ADD_ENTITY,
|
||||
REMOVE_ENTITY;
|
||||
}
|
||||
|
||||
public static class CreateTeam {
|
||||
private Component displayName;
|
||||
private boolean allowFriendlyFire;
|
||||
private boolean canSeeFriendlyInvisibles;
|
||||
private FS_NameTagVisibility nameTagVisibility;
|
||||
private FS_CollisionRule collisionRule;
|
||||
private FS_Color color;
|
||||
private Component prefix;
|
||||
private Component suffix;
|
||||
private List<String> entities;
|
||||
|
||||
public CreateTeam(Component displayName, boolean allowFriendlyFire, boolean canSeeFriendlyInvisibles, FS_NameTagVisibility nameTagVisibility, FS_CollisionRule collisionRule, FS_Color color, Component prefix, Component suffix, List<String> entities) {
|
||||
this.displayName = displayName;
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
this.collisionRule = collisionRule;
|
||||
this.color = color;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public Component getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public boolean isAllowFriendlyFire() {
|
||||
return allowFriendlyFire;
|
||||
}
|
||||
|
||||
public void setAllowFriendlyFire(boolean allowFriendlyFire) {
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
}
|
||||
|
||||
public boolean isCanSeeFriendlyInvisibles() {
|
||||
return canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public void setCanSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public FS_NameTagVisibility getNameTagVisibility() {
|
||||
return nameTagVisibility;
|
||||
}
|
||||
|
||||
public void setNameTagVisibility(FS_NameTagVisibility nameTagVisibility) {
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
}
|
||||
|
||||
public FS_CollisionRule getCollisionRule() {
|
||||
return collisionRule;
|
||||
}
|
||||
|
||||
public void setCollisionRule(FS_CollisionRule collisionRule) {
|
||||
this.collisionRule = collisionRule;
|
||||
}
|
||||
|
||||
public FS_Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(FS_Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Component getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(Component prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public Component getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(Component suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public List<String> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public void setEntities(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoveTeam {
|
||||
|
||||
}
|
||||
|
||||
public static class UpdateTeam {
|
||||
private Component displayName;
|
||||
private boolean allowFriendlyFire;
|
||||
private boolean canSeeFriendlyInvisibles;
|
||||
private FS_NameTagVisibility nameTagVisibility;
|
||||
private FS_CollisionRule collisionRule;
|
||||
private FS_Color color;
|
||||
private Component prefix;
|
||||
private Component suffix;
|
||||
|
||||
public UpdateTeam(Component displayName, boolean allowFriendlyFire, boolean canSeeFriendlyInvisibles, FS_NameTagVisibility nameTagVisibility, FS_CollisionRule collisionRule, FS_Color color, Component prefix, Component suffix) {
|
||||
this.displayName = displayName;
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
this.collisionRule = collisionRule;
|
||||
this.color = color;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public Component getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public boolean isAllowFriendlyFire() {
|
||||
return allowFriendlyFire;
|
||||
}
|
||||
|
||||
public void setAllowFriendlyFire(boolean allowFriendlyFire) {
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
}
|
||||
|
||||
public boolean isCanSeeFriendlyInvisibles() {
|
||||
return canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public void setCanSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public FS_NameTagVisibility getNameTagVisibility() {
|
||||
return nameTagVisibility;
|
||||
}
|
||||
|
||||
public void setNameTagVisibility(FS_NameTagVisibility nameTagVisibility) {
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
}
|
||||
|
||||
public FS_CollisionRule getCollisionRule() {
|
||||
return collisionRule;
|
||||
}
|
||||
|
||||
public void setCollisionRule(FS_CollisionRule collisionRule) {
|
||||
this.collisionRule = collisionRule;
|
||||
}
|
||||
|
||||
public FS_Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(FS_Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Component getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(Component prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public Component getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(Component suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AddEntity {
|
||||
private List<String> entities;
|
||||
|
||||
public AddEntity(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public List<String> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public void setEntities(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoveEntity {
|
||||
private List<String> entities;
|
||||
|
||||
public RemoveEntity(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public List<String> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public void setEntities(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import de.oliver.fancysitula.api.IFancySitula;
|
||||
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public abstract class FS_ClientboundPacket {
|
||||
|
||||
/**
|
||||
* Creates the packet object.
|
||||
* For internal use only.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public abstract Object createPacket();
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
* For internal use only.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
protected abstract void sendPacketTo(FS_RealPlayer player);
|
||||
|
||||
/**
|
||||
* Sends the packet to the player.
|
||||
*/
|
||||
public final void send(FS_RealPlayer player) {
|
||||
IFancySitula.LOGGER.debug("Sending packet '" + this.getClass().getSimpleName() + "' to " + player.getBukkitPlayer().getName());
|
||||
|
||||
sendPacketTo(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to remove players from the client's player list.
|
||||
*/
|
||||
public abstract class FS_ClientboundPlayerInfoRemovePacket extends FS_ClientboundPacket {
|
||||
|
||||
protected List<UUID> uuids;
|
||||
|
||||
public FS_ClientboundPlayerInfoRemovePacket(List<UUID> uuids) {
|
||||
this.uuids = uuids;
|
||||
}
|
||||
|
||||
public List<UUID> getUuids() {
|
||||
return uuids;
|
||||
}
|
||||
|
||||
public void setUuids(List<UUID> uuids) {
|
||||
this.uuids = uuids;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import de.oliver.fancysitula.api.utils.FS_GameProfile;
|
||||
import de.oliver.fancysitula.api.utils.FS_GameType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used to update the player list of the client.
|
||||
*/
|
||||
public abstract class FS_ClientboundPlayerInfoUpdatePacket extends FS_ClientboundPacket {
|
||||
|
||||
protected EnumSet<Action> actions;
|
||||
protected List<Entry> entries;
|
||||
|
||||
public FS_ClientboundPlayerInfoUpdatePacket(EnumSet<Action> actions, List<Entry> entries) {
|
||||
this.actions = actions;
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public EnumSet<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void setActions(EnumSet<Action> actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
public List<Entry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void setEntries(List<Entry> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public enum Action {
|
||||
ADD_PLAYER,
|
||||
INITIALIZE_CHAT,
|
||||
UPDATE_GAME_MODE,
|
||||
UPDATE_LISTED,
|
||||
UPDATE_LATENCY,
|
||||
UPDATE_DISPLAY_NAME,
|
||||
}
|
||||
|
||||
public record Entry(UUID uuid,
|
||||
FS_GameProfile profile,
|
||||
boolean listed,
|
||||
int latency,
|
||||
FS_GameType gameMode,
|
||||
@Nullable Component displayName) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to remove entities from the client's world.
|
||||
*/
|
||||
public abstract class FS_ClientboundRemoveEntitiesPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected List<Integer> entityIds;
|
||||
|
||||
/**
|
||||
* @param entityIds IDs of the entities to remove
|
||||
*/
|
||||
public FS_ClientboundRemoveEntitiesPacket(List<Integer> entityIds) {
|
||||
this.entityIds = entityIds;
|
||||
}
|
||||
|
||||
public List<Integer> getEntityIds() {
|
||||
return entityIds;
|
||||
}
|
||||
|
||||
public void setEntityIds(List<Integer> entityIds) {
|
||||
this.entityIds = entityIds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
public abstract class FS_ClientboundRotateHeadPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected float headYaw;
|
||||
|
||||
public FS_ClientboundRotateHeadPacket(int entityId, float headYaw) {
|
||||
this.entityId = entityId;
|
||||
this.headYaw = headYaw;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public float getHeadYaw() {
|
||||
return headYaw;
|
||||
}
|
||||
|
||||
public void setHeadYaw(float headYaw) {
|
||||
this.headYaw = headYaw;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FS_ClientboundSetEntityDataPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected List<EntityData> entityData;
|
||||
|
||||
public FS_ClientboundSetEntityDataPacket(int entityId, List<EntityData> entityData) {
|
||||
this.entityId = entityId;
|
||||
this.entityData = entityData;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public List<EntityData> getEntityData() {
|
||||
return entityData;
|
||||
}
|
||||
|
||||
public void setEntityData(List<EntityData> entityData) {
|
||||
this.entityData = entityData;
|
||||
}
|
||||
|
||||
public static class EntityData {
|
||||
private EntityDataAccessor accessor;
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* @param accessor can be found in {@link de.oliver.fancysitula.api.utils.entityData}
|
||||
* @param value must be the correct type for the accessor (see accessor javadoc)
|
||||
*/
|
||||
public EntityData(EntityDataAccessor accessor, Object value) {
|
||||
this.accessor = accessor;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public EntityDataAccessor getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
public void setAccessor(EntityDataAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityClassName the class name of the entity (e.g. "net.minecraft.world.entity.Display$TextDisplay")
|
||||
* @param accessorFieldName the field name of the accessor (typically starts with "DATA_" and ends with "_ID")
|
||||
*/
|
||||
public record EntityDataAccessor(String entityClassName, String accessorFieldName) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class FS_ClientboundSetEquipmentPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected Map<FS_EquipmentSlot, ItemStack> equipment;
|
||||
|
||||
public FS_ClientboundSetEquipmentPacket(int entityId, Map<FS_EquipmentSlot, ItemStack> equipment) {
|
||||
this.entityId = entityId;
|
||||
this.equipment = equipment;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public Map<FS_EquipmentSlot, ItemStack> getEquipment() {
|
||||
return equipment;
|
||||
}
|
||||
|
||||
public void setEquipment(Map<FS_EquipmentSlot, ItemStack> equipment) {
|
||||
this.equipment = equipment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class FS_ClientboundSetPassengersPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected List<Integer> passengers;
|
||||
|
||||
public FS_ClientboundSetPassengersPacket(int entityId, List<Integer> passengers) {
|
||||
this.entityId = entityId;
|
||||
this.passengers = passengers;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public List<Integer> getPassengers() {
|
||||
return passengers;
|
||||
}
|
||||
|
||||
public void setPassengers(List<Integer> passengers) {
|
||||
this.passengers = passengers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
public abstract class FS_ClientboundTeleportEntityPacket extends FS_ClientboundPacket {
|
||||
|
||||
protected int entityId;
|
||||
protected double x;
|
||||
protected double y;
|
||||
protected double z;
|
||||
protected float yaw;
|
||||
protected float pitch;
|
||||
protected boolean onGround;
|
||||
|
||||
public FS_ClientboundTeleportEntityPacket(int entityId, double x, double y, double z, float yaw, float pitch, boolean onGround) {
|
||||
this.entityId = entityId;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.onGround = onGround;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return onGround;
|
||||
}
|
||||
|
||||
public void setOnGround(boolean onGround) {
|
||||
this.onGround = onGround;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.packets;
|
||||
|
||||
public enum FS_Color {
|
||||
BLACK(0),
|
||||
DARK_BLUE(1),
|
||||
DARK_GREEN(2),
|
||||
DARK_AQUA(3),
|
||||
DARK_RED(4),
|
||||
DARK_PURPLE(5),
|
||||
GOLD(6),
|
||||
GRAY(7),
|
||||
DARK_GRAY(8),
|
||||
BLUE(9),
|
||||
GREEN(10),
|
||||
AQUA(11),
|
||||
RED(12),
|
||||
LIGHT_PURPLE(13),
|
||||
YELLOW(14),
|
||||
WHITE(15);
|
||||
|
||||
|
||||
private final int id;
|
||||
|
||||
FS_Color(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.oliver.fancysitula.api.teams;
|
||||
|
||||
public enum FS_CollisionRule {
|
||||
ALWAYS("always"),
|
||||
NEVER("never"),
|
||||
PUSH_OTHER_TEAMS("pushOtherTeams"),
|
||||
PUSH_OWN_TEAM("pushOwnTeam");
|
||||
|
||||
private final String name;
|
||||
|
||||
FS_CollisionRule(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.oliver.fancysitula.api.teams;
|
||||
|
||||
public enum FS_NameTagVisibility {
|
||||
ALWAYS("always"),
|
||||
NEVER("never"),
|
||||
HIDE_FOR_OTHER_TEAMS("hideForOtherTeams"),
|
||||
HIDE_FOR_OWN_TEAM("hideForOwnTeam");
|
||||
|
||||
private final String name;
|
||||
|
||||
FS_NameTagVisibility(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package de.oliver.fancysitula.api.teams;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_Color;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FS_Team {
|
||||
|
||||
private String teamName;
|
||||
private Component displayName;
|
||||
private boolean allowFriendlyFire;
|
||||
private boolean canSeeFriendlyInvisibles;
|
||||
private FS_NameTagVisibility nameTagVisibility;
|
||||
private FS_CollisionRule collisionRule;
|
||||
private FS_Color color;
|
||||
private Component prefix;
|
||||
private Component suffix;
|
||||
private List<String> entities;
|
||||
|
||||
public FS_Team(String teamName, Component displayName, boolean allowFriendlyFire, boolean canSeeFriendlyInvisibles, FS_NameTagVisibility nameTagVisibility, FS_CollisionRule collisionRule, FS_Color color, Component prefix, Component suffix, List<String> entities) {
|
||||
this.teamName = teamName;
|
||||
this.displayName = displayName;
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
this.collisionRule = collisionRule;
|
||||
this.color = color;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public String getTeamName() {
|
||||
return teamName;
|
||||
}
|
||||
|
||||
public void setTeamName(String teamName) {
|
||||
this.teamName = teamName;
|
||||
}
|
||||
|
||||
public Component getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public boolean isAllowFriendlyFire() {
|
||||
return allowFriendlyFire;
|
||||
}
|
||||
|
||||
public void setAllowFriendlyFire(boolean allowFriendlyFire) {
|
||||
this.allowFriendlyFire = allowFriendlyFire;
|
||||
}
|
||||
|
||||
public boolean isCanSeeFriendlyInvisibles() {
|
||||
return canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public void setCanSeeFriendlyInvisibles(boolean canSeeFriendlyInvisibles) {
|
||||
this.canSeeFriendlyInvisibles = canSeeFriendlyInvisibles;
|
||||
}
|
||||
|
||||
public FS_NameTagVisibility getNameTagVisibility() {
|
||||
return nameTagVisibility;
|
||||
}
|
||||
|
||||
public void setNameTagVisibility(FS_NameTagVisibility nameTagVisibility) {
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
}
|
||||
|
||||
public FS_CollisionRule getCollisionRule() {
|
||||
return collisionRule;
|
||||
}
|
||||
|
||||
public void setCollisionRule(FS_CollisionRule collisionRule) {
|
||||
this.collisionRule = collisionRule;
|
||||
}
|
||||
|
||||
public FS_Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(FS_Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Component getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(Component prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public Component getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(Component suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public List<String> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public void setEntities(List<String> entities) {
|
||||
this.entities = entities;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.oliver.fancysitula.api.utils;
|
||||
|
||||
public class AngelConverter {
|
||||
|
||||
public static byte degreesToVanillaByte(float degrees) {
|
||||
return (byte) Math.floor(degrees * 256.0F / 360.0F);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.oliver.fancysitula.api.utils;
|
||||
|
||||
public enum FS_EquipmentSlot {
|
||||
MAINHAND,
|
||||
OFFHAND,
|
||||
FEET,
|
||||
LEGS,
|
||||
CHEST,
|
||||
HEAD,
|
||||
BODY,
|
||||
;
|
||||
|
||||
public static FS_EquipmentSlot fromBukkit(org.bukkit.inventory.EquipmentSlot equipmentSlot) {
|
||||
return switch (equipmentSlot) {
|
||||
case HAND -> MAINHAND;
|
||||
case OFF_HAND -> OFFHAND;
|
||||
case FEET -> FEET;
|
||||
case LEGS -> LEGS;
|
||||
case CHEST -> CHEST;
|
||||
case HEAD -> HEAD;
|
||||
case BODY -> BODY;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package de.oliver.fancysitula.api.utils;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class FS_GameProfile {
|
||||
|
||||
private UUID uuid;
|
||||
private String name;
|
||||
private Map<String, Property> properties;
|
||||
|
||||
public FS_GameProfile(UUID uuid, String name, Map<String, Property> properties) {
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public FS_GameProfile(UUID uuid, String name) {
|
||||
this(uuid, name, new HashMap<>());
|
||||
}
|
||||
|
||||
public static FS_GameProfile fromBukkit(PlayerProfile gameProfile) {
|
||||
FS_GameProfile fsGameProfile = new FS_GameProfile(gameProfile.getId(), gameProfile.getName());
|
||||
|
||||
for (ProfileProperty property : gameProfile.getProperties()) {
|
||||
fsGameProfile.getProperties().put(property.getName(), new FS_GameProfile.Property(property.getName(), property.getValue(), property.getSignature()));
|
||||
}
|
||||
|
||||
return fsGameProfile;
|
||||
}
|
||||
|
||||
public UUID getUUID() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUUID(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Map<String, Property> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, Property> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public record Property(String name, String value, String signature) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.oliver.fancysitula.api.utils;
|
||||
|
||||
public enum FS_GameType {
|
||||
SURVIVAL(0, "survival"),
|
||||
CREATIVE(1, "creative"),
|
||||
ADVENTURE(2, "adventure"),
|
||||
SPECTATOR(3, "spectator");
|
||||
|
||||
private final int id;
|
||||
private final String name;
|
||||
|
||||
FS_GameType(int id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package de.oliver.fancysitula.api.utils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public enum ServerVersion {
|
||||
|
||||
v1_21_4("1.21.4", 769),
|
||||
v1_21_3("1.21.3", 768),
|
||||
v1_21_1("1.21.1", 767),
|
||||
v1_21("1.21", 767),
|
||||
v1_20_6("1.20.6", 766),
|
||||
v1_20_5("1.20.5", 766),
|
||||
;
|
||||
|
||||
private final String version;
|
||||
private final int protocolVersion;
|
||||
|
||||
ServerVersion(String version, int protocolVersion) {
|
||||
this.version = version;
|
||||
this.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
public static ServerVersion getByProtocolVersion(int protocolVersion) {
|
||||
for (ServerVersion version : values()) {
|
||||
if (version.getProtocolVersion() == protocolVersion) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ServerVersion getByVersion(String version) {
|
||||
for (ServerVersion serverVersion : values()) {
|
||||
if (serverVersion.getVersion().equals(version)) {
|
||||
return serverVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<String> getSupportedVersions() {
|
||||
return Arrays.stream(values())
|
||||
.map(ServerVersion::getVersion)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static boolean isVersionSupported(String version) {
|
||||
return getByVersion(version) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current server version of the server the plugin is running on
|
||||
*/
|
||||
public static ServerVersion getCurrentVersion() {
|
||||
return getByVersion(Bukkit.getMinecraftVersion());
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public int getProtocolVersion() {
|
||||
return protocolVersion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.oliver.fancysitula.api.utils.entityData;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
|
||||
public class FS_BlockDisplayData {
|
||||
|
||||
/**
|
||||
* Use {@link org.bukkit.block.Block} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor BLOCK = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$BlockDisplay", "DATA_BLOCK_STATE_ID");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package de.oliver.fancysitula.api.utils.entityData;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
|
||||
public class FS_DisplayData {
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TRANSFORMATION_INTERPOLATION_DURATION = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor POS_ROT_INTERPOLATION_DURATION = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_POS_ROT_INTERPOLATION_DURATION_ID");
|
||||
|
||||
/**
|
||||
* Use {@link org.joml.Vector3f} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TRANSLATION = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_TRANSLATION_ID");
|
||||
|
||||
/**
|
||||
* Use {@link org.joml.Vector3f} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor SCALE = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_SCALE_ID");
|
||||
|
||||
/**
|
||||
* Use {@link org.joml.Quaternionf} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor LEFT_ROTATION = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_LEFT_ROTATION_ID");
|
||||
|
||||
/**
|
||||
* Use {@link org.joml.Quaternionf} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor RIGHT_ROTATION = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_RIGHT_ROTATION_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Byte} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor BILLBOARD_RENDER_CONSTRAINTS = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_BILLBOARD_RENDER_CONSTRAINTS_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor BRIGHTNESS_OVERRIDE = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_BRIGHTNESS_OVERRIDE_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Float} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor VIEW_RANGE = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_VIEW_RANGE_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Float} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor SHADOW_RADIUS = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_SHADOW_RADIUS_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Float} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor SHADOW_STRENGTH = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_SHADOW_STRENGTH_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Float} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor WIDTH = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_WIDTH_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Float} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor HEIGHT = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_HEIGHT_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor GLOW_COLOR_OVERRIDE = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display", "DATA_GLOW_COLOR_OVERRIDE_ID");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package de.oliver.fancysitula.api.utils.entityData;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
|
||||
public class FS_EntityData {
|
||||
|
||||
/**
|
||||
* Use {@link Byte} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor SHARED_FLAGS = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_SHARED_FLAGS_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor AIR_SUPPLY = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_AIR_SUPPLY_ID");
|
||||
|
||||
/**
|
||||
* Use {@link java.util.Optional<net.kyori.adventure.text.Component>} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor CUSTOM_NAME = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_CUSTOM_NAME");
|
||||
|
||||
/**
|
||||
* Use {@link Boolean} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor CUSTOM_NAME_VISIBLE = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_CUSTOM_NAME_VISIBLE");
|
||||
|
||||
/**
|
||||
* Use {@link Boolean} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor SILENT = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_SILENT");
|
||||
|
||||
/**
|
||||
* Use {@link Boolean} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor NO_GRAVITY = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_NO_GRAVITY");
|
||||
|
||||
// TODO: Add DATA_POSE
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TICKS_FROZEN = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Entity", "DATA_TICKS_FROZEN");
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.oliver.fancysitula.api.utils.entityData;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
|
||||
public class FS_ItemDisplayData {
|
||||
|
||||
/**
|
||||
* Use {@link org.bukkit.inventory.ItemStack} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor ITEM = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$ItemDisplay", "DATA_ITEM_STACK_ID");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancysitula.api.utils.entityData;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
|
||||
|
||||
public class FS_TextDisplayData {
|
||||
|
||||
/**
|
||||
* Use {@link net.kyori.adventure.text.Component} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TEXT = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_TEXT_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor LINE_WIDTH = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_LINE_WIDTH_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Integer} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor BACKGROUND = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_BACKGROUND_COLOR_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Byte} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor TEXT_OPACITY = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_TEXT_OPACITY_ID");
|
||||
|
||||
/**
|
||||
* Use {@link Byte} as value
|
||||
*/
|
||||
public static final FS_ClientboundSetEntityDataPacket.EntityDataAccessor STYLE_FLAGS = new FS_ClientboundSetEntityDataPacket.EntityDataAccessor("net.minecraft.world.entity.Display$TextDisplay", "DATA_STYLE_FLAGS_ID");
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package de.oliver.fancysitula.api.utils.reflections;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
private static Unsafe getUnsafe() throws Exception {
|
||||
Field field = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
field.setAccessible(true);
|
||||
return (Unsafe) field.get(null);
|
||||
}
|
||||
|
||||
public static <T> T createUnsafeInstance(Class<T> clazz) throws Exception {
|
||||
Unsafe unsafe = getUnsafe();
|
||||
return (T) unsafe.allocateInstance(clazz);
|
||||
}
|
||||
|
||||
public static <T> T createInstance(Class<T> clazz) throws Exception {
|
||||
Constructor<T> constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
}
|
||||
|
||||
public static Object getField(Object object, String fieldName) throws Exception {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return field.get(object);
|
||||
}
|
||||
|
||||
public static void setField(Object object, String fieldName, Object value) throws Exception {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(object, value);
|
||||
}
|
||||
|
||||
public static void setFinalField(Object target, String fieldName, Object value) throws Exception {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
|
||||
// Use Unsafe to modify the final field
|
||||
Unsafe unsafe = getUnsafe();
|
||||
long offset = unsafe.objectFieldOffset(field);
|
||||
if (field.getType() == int.class) {
|
||||
unsafe.putInt(target, offset, (int) value);
|
||||
} else if (field.getType() == long.class) {
|
||||
unsafe.putLong(target, offset, (long) value);
|
||||
} else if (field.getType() == double.class) {
|
||||
unsafe.putDouble(target, offset, (double) value);
|
||||
} else if (field.getType() == float.class) {
|
||||
unsafe.putFloat(target, offset, (float) value);
|
||||
} else if (field.getType() == boolean.class) {
|
||||
unsafe.putBoolean(target, offset, (boolean) value);
|
||||
} else if (field.getType() == byte.class) {
|
||||
unsafe.putByte(target, offset, (byte) value);
|
||||
} else if (field.getType() == short.class) {
|
||||
unsafe.putShort(target, offset, (short) value);
|
||||
} else if (field.getType() == char.class) {
|
||||
unsafe.putChar(target, offset, (char) value);
|
||||
} else {
|
||||
unsafe.putObject(target, offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T getStaticField(Class<?> clazz, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = clazz.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(null);
|
||||
}
|
||||
}
|
||||
87
libraries/packets/build.gradle.kts
Normal file
87
libraries/packets/build.gradle.kts
Normal file
@@ -0,0 +1,87 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "de.oliver"
|
||||
version = "0.0.13"
|
||||
description = "Simple, lightweight and fast library for minecraft internals"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven(url = "https://repo.papermc.io/repository/maven-public/")
|
||||
maven(url = "https://repo.fancyplugins.de/releases")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||
|
||||
implementation(project(":libraries:packets:api"))
|
||||
implementation(project(":libraries:packets:factories"))
|
||||
implementation(project(":libraries:packets:implementations:1_21_4"))
|
||||
implementation(project(":libraries:packets:implementations:1_21_3"))
|
||||
implementation(project(":libraries:packets:implementations:1_20_6"))
|
||||
implementation("de.oliver.FancyAnalytics:logger:0.0.4")
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier.set("")
|
||||
configurations = listOf(project.configurations["runtimeClasspath"])
|
||||
dependencies {
|
||||
include(dependency("de.oliver:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "fancypluginsReleases"
|
||||
url = uri("https://repo.fancyplugins.de/releases")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "fancypluginsSnapshots"
|
||||
url = uri("https://repo.fancyplugins.de/snapshots")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("shadow") {
|
||||
groupId = project.group.toString()
|
||||
version = project.version.toString()
|
||||
artifact(shadowJar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 21
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
processResources {
|
||||
filteringCharset = Charsets.UTF_8.name()
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
28
libraries/packets/factories/build.gradle.kts
Normal file
28
libraries/packets/factories/build.gradle.kts
Normal file
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||
compileOnly(project(":libraries:packets:api"))
|
||||
compileOnly(project(":libraries:packets:implementations:1_20_6"))
|
||||
compileOnly(project(":libraries:packets:implementations:1_21_3"))
|
||||
compileOnly(project(":libraries:packets:implementations:1_21_4"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 21
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package de.oliver.fancysitula.factories;
|
||||
|
||||
import de.oliver.fancysitula.api.entities.FS_Entity;
|
||||
import de.oliver.fancysitula.api.entities.FS_Player;
|
||||
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EntityFactory {
|
||||
|
||||
public void spawnEntityFor(FS_RealPlayer player, FS_Entity entity) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FancySitula.PACKET_FACTORY.createAddEntityPacket(
|
||||
entity.getId(),
|
||||
entity.getUuid(),
|
||||
entity.getType(),
|
||||
entity.getX(),
|
||||
entity.getY(),
|
||||
entity.getZ(),
|
||||
entity.getYaw(),
|
||||
entity.getPitch(),
|
||||
entity.getHeadYaw(),
|
||||
entity.getVelocityX(),
|
||||
entity.getVelocityY(),
|
||||
entity.getVelocityZ(),
|
||||
entity.getData()
|
||||
).send(player);
|
||||
|
||||
setEntityDataFor(player, entity);
|
||||
}
|
||||
|
||||
public void despawnEntityFor(FS_RealPlayer player, FS_Entity entity) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FancySitula.PACKET_FACTORY.createRemoveEntitiesPacket(
|
||||
List.of(entity.getId())
|
||||
)
|
||||
.send(player);
|
||||
}
|
||||
|
||||
public void setEntityDataFor(FS_RealPlayer player, FS_Entity entity) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity.getEntityData().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FancySitula.PACKET_FACTORY.createSetEntityDataPacket(
|
||||
entity.getId(),
|
||||
entity.getEntityData()
|
||||
).send(player);
|
||||
}
|
||||
|
||||
public void setEntityEquipmentFor(FS_RealPlayer player, FS_Player entity) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FancySitula.PACKET_FACTORY.createSetEquipmentPacket(
|
||||
entity.getId(),
|
||||
entity.getEquipment()
|
||||
).send(player);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.oliver.fancysitula.factories;
|
||||
|
||||
public class FancySitula {
|
||||
|
||||
public static final PacketFactory PACKET_FACTORY = new PacketFactory();
|
||||
public static final EntityFactory ENTITY_FACTORY = new EntityFactory();
|
||||
public static final TeamFactory TEAM_FACTORY = new TeamFactory();
|
||||
}
|
||||
@@ -0,0 +1,549 @@
|
||||
package de.oliver.fancysitula.factories;
|
||||
|
||||
import de.oliver.fancysitula.api.packets.*;
|
||||
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
|
||||
import de.oliver.fancysitula.api.utils.ServerVersion;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Factory class for creating packet instances based on the server version
|
||||
*/
|
||||
public class PacketFactory {
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoUpdatePacket instance based on the server version
|
||||
*
|
||||
* @param actions EnumSet of {@link FS_ClientboundPlayerInfoUpdatePacket.Action} to perform
|
||||
* @param entries List of {@link FS_ClientboundPlayerInfoUpdatePacket.Entry} to update
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoUpdatePacket createPlayerInfoUpdatePacket(
|
||||
ServerVersion serverVersion, EnumSet<FS_ClientboundPlayerInfoUpdatePacket.Action> actions,
|
||||
List<FS_ClientboundPlayerInfoUpdatePacket.Entry> entries) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoUpdatePacket instance based on the current server version
|
||||
*
|
||||
* @param actions EnumSet of {@link FS_ClientboundPlayerInfoUpdatePacket.Action} to perform
|
||||
* @param entries List of {@link FS_ClientboundPlayerInfoUpdatePacket.Entry} to update
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoUpdatePacket createPlayerInfoUpdatePacket(
|
||||
EnumSet<FS_ClientboundPlayerInfoUpdatePacket.Action> actions,
|
||||
List<FS_ClientboundPlayerInfoUpdatePacket.Entry> entries) {
|
||||
return createPlayerInfoUpdatePacket(ServerVersion.getCurrentVersion(), actions, entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundAddEntityPacket instance based on the server version
|
||||
*
|
||||
* @param yaw in degrees (0 - 360)
|
||||
* @param pitch in degrees (0 - 360)
|
||||
* @param headYaw in degrees (0 - 360)
|
||||
*/
|
||||
public FS_ClientboundAddEntityPacket createAddEntityPacket(
|
||||
ServerVersion serverVersion,
|
||||
int entityId,
|
||||
UUID entityUUID,
|
||||
EntityType entityType,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
float headYaw,
|
||||
int velocityX,
|
||||
int velocityY,
|
||||
int velocityZ,
|
||||
int data) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundAddEntityPacket instance based on the current server version
|
||||
*
|
||||
* @param yaw in degrees (0 - 360)
|
||||
* @param pitch in degrees (0 - 360)
|
||||
* @param headYaw in degrees (0 - 360)
|
||||
*/
|
||||
public FS_ClientboundAddEntityPacket createAddEntityPacket(
|
||||
int entityId,
|
||||
UUID entityUUID,
|
||||
EntityType entityType,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
float headYaw,
|
||||
int velocityX,
|
||||
int velocityY,
|
||||
int velocityZ,
|
||||
int data) {
|
||||
return createAddEntityPacket(ServerVersion.getCurrentVersion(), entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoRemovePacket instance based on the server version
|
||||
*
|
||||
* @param uuids UUIDs of the players to remove
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoRemovePacket createPlayerInfoRemovePacket(ServerVersion serverVersion, List<UUID> uuids) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundPlayerInfoRemovePacketImpl(uuids);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundPlayerInfoRemovePacketImpl(uuids);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundPlayerInfoRemovePacketImpl(uuids);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoRemovePacket instance based on the current server version
|
||||
*
|
||||
* @param uuids UUIDs of the players to remove
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoRemovePacket createPlayerInfoRemovePacket(List<UUID> uuids) {
|
||||
return createPlayerInfoRemovePacket(ServerVersion.getCurrentVersion(), uuids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoRemovePacket instance based on the server version
|
||||
*
|
||||
* @param uuid UUID of the player to remove
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoRemovePacket createPlayerInfoRemovePacket(ServerVersion serverVersion, UUID uuid) {
|
||||
return createPlayerInfoRemovePacket(serverVersion, List.of(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundPlayerInfoRemovePacket instance based on the current server version
|
||||
*
|
||||
* @param uuid UUID of the player to remove
|
||||
*/
|
||||
public FS_ClientboundPlayerInfoRemovePacket createPlayerInfoRemovePacket(UUID uuid) {
|
||||
return createPlayerInfoRemovePacket(ServerVersion.getCurrentVersion(), uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundRemoveEntitiesPacket instance based on the server version
|
||||
*
|
||||
* @param entityIds IDs of the entities to remove
|
||||
*/
|
||||
public FS_ClientboundRemoveEntitiesPacket createRemoveEntitiesPacket(ServerVersion serverVersion, List<Integer> entityIds) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundRemoveEntitiesPacketImpl(entityIds);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundRemoveEntitiesPacketImpl(entityIds);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundRemoveEntitiesPacketImpl(entityIds);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundRemoveEntitiesPacket instance based on the current server version
|
||||
*
|
||||
* @param entityIds IDs of the entities to remove
|
||||
*/
|
||||
public FS_ClientboundRemoveEntitiesPacket createRemoveEntitiesPacket(List<Integer> entityIds) {
|
||||
return createRemoveEntitiesPacket(ServerVersion.getCurrentVersion(), entityIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundTeleportEntityPacket instance based on the server version
|
||||
*
|
||||
* @param entityId ID of the entity to teleport
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param z Z coordinate
|
||||
* @param yaw Yaw in degrees (0 - 360)
|
||||
* @param pitch Pitch in degrees (0 - 360)
|
||||
* @param onGround Whether the entity is on the ground
|
||||
*/
|
||||
public FS_ClientboundTeleportEntityPacket createTeleportEntityPacket(
|
||||
ServerVersion serverVersion,
|
||||
int entityId,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
boolean onGround
|
||||
) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundTeleportEntityPacket instance based on the current server version
|
||||
*
|
||||
* @param entityId ID of the entity to teleport
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param z Z coordinate
|
||||
* @param yaw Yaw in degrees (0 - 360)
|
||||
* @param pitch Pitch in degrees (0 - 360)
|
||||
* @param onGround Whether the entity is on the ground
|
||||
*/
|
||||
public FS_ClientboundTeleportEntityPacket createTeleportEntityPacket(
|
||||
int entityId,
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
boolean onGround
|
||||
) {
|
||||
return createTeleportEntityPacket(ServerVersion.getCurrentVersion(), entityId, x, y, z, yaw, pitch, onGround);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundRotateHeadPacket instance based on the server version
|
||||
*
|
||||
* @param entityId ID of the entity to rotate the head of
|
||||
* @param headYaw Yaw of the head in degrees (0 - 360)
|
||||
*/
|
||||
public FS_ClientboundRotateHeadPacket createRotateHeadPacket(ServerVersion serverVersion, int entityId, float headYaw) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundRotateHeadPacket instance based on the current server version
|
||||
*
|
||||
* @param entityId ID of the entity to rotate the head of
|
||||
* @param headYaw Yaw of the head in degrees (0 - 360)
|
||||
*/
|
||||
public FS_ClientboundRotateHeadPacket createRotateHeadPacket(int entityId, float headYaw) {
|
||||
return createRotateHeadPacket(ServerVersion.getCurrentVersion(), entityId, headYaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetEntityDataPacket instance based on the server version
|
||||
*
|
||||
* @param entityId ID of the entity to set the data of
|
||||
* @param entityData List of {@link FS_ClientboundSetEntityDataPacket.EntityData} to set
|
||||
*/
|
||||
public FS_ClientboundSetEntityDataPacket createSetEntityDataPacket(
|
||||
ServerVersion serverVersion, int entityId, List<FS_ClientboundSetEntityDataPacket.EntityData> entityData) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetEntityDataPacket instance based on the current server version
|
||||
*
|
||||
* @param entityId ID of the entity to set the data of
|
||||
* @param entityData List of {@link FS_ClientboundSetEntityDataPacket.EntityData} to set
|
||||
*/
|
||||
public FS_ClientboundSetEntityDataPacket createSetEntityDataPacket(int entityId, List<FS_ClientboundSetEntityDataPacket.EntityData> entityData) {
|
||||
return createSetEntityDataPacket(ServerVersion.getCurrentVersion(), entityId, entityData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetEquipmentPacket instance based on the server version
|
||||
*
|
||||
* @param entityId ID of the entity to set the equipment of
|
||||
* @param equipment Map of {@link org.bukkit.inventory.EquipmentSlot} and {@link org.bukkit.inventory.ItemStack} to set
|
||||
*/
|
||||
public FS_ClientboundSetEquipmentPacket createSetEquipmentPacket(ServerVersion serverVersion, int entityId, Map<FS_EquipmentSlot, ItemStack> equipment) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetEquipmentPacket instance based on the current server version
|
||||
*
|
||||
* @param entityId ID of the entity to set the equipment of
|
||||
* @param equipment Map of {@link org.bukkit.inventory.EquipmentSlot} and {@link org.bukkit.inventory.ItemStack} to set
|
||||
*/
|
||||
public FS_ClientboundSetEquipmentPacket createSetEquipmentPacket(int entityId, Map<FS_EquipmentSlot, ItemStack> equipment) {
|
||||
return createSetEquipmentPacket(ServerVersion.getCurrentVersion(), entityId, equipment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetPassengersPacket instance based on the server version
|
||||
*
|
||||
* @param entityId ID of the vehicle entity
|
||||
* @param passengers List of entity IDs to set as passengers
|
||||
*/
|
||||
public FS_ClientboundSetPassengersPacket createSetPassengersPacket(
|
||||
ServerVersion serverVersion, int entityId, List<Integer> passengers) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundSetPassengersPacketImpl(entityId, passengers);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundSetPassengersPacketImpl(entityId, passengers);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundSetPassengersPacketImpl(entityId, passengers);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundSetPassengersPacket instance based on the current server version
|
||||
*
|
||||
* @param entityId ID of the vehicle entity
|
||||
* @param passengers List of entity IDs to set as passengers
|
||||
*/
|
||||
public FS_ClientboundSetPassengersPacket createSetPassengersPacket(int entityId, List<Integer> passengers) {
|
||||
return createSetPassengersPacket(ServerVersion.getCurrentVersion(), entityId, passengers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates and returns a FS_ClientboundCreateOrUpdateTeamPacket based on the given server version and team information.
|
||||
*
|
||||
* @param serverVersion the version of the server for which the packet is to be created
|
||||
* @param teamName the name of the team to be created or updated
|
||||
* @param createTeam an instance of FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam containing the team creation or update details
|
||||
* @return a FS_ClientboundCreateOrUpdateTeamPacket instance corresponding to the specified server version and team details
|
||||
* @throws IllegalArgumentException if the provided server version is not supported
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(ServerVersion serverVersion, String teamName, FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam createTeam) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an FS_ClientboundCreateOrUpdateTeamPacket for the given team name and creation details.
|
||||
*
|
||||
* @param teamName The name of the team to create or update.
|
||||
* @param createTeam The details of the team creation or update.
|
||||
* @return An instance of FS_ClientboundCreateOrUpdateTeamPacket containing the creation or update details.
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(String teamName, FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam createTeam) {
|
||||
return createCreateOrUpdateTeamPacket(ServerVersion.getCurrentVersion(), teamName, createTeam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet for creating or updating a team based on the specified server version.
|
||||
*
|
||||
* @param serverVersion The version of the server.
|
||||
* @param teamName The name of the team.
|
||||
* @param removeTeam Information about whether to remove the team.
|
||||
* @return The packet for creating or updating the team.
|
||||
* @throws IllegalArgumentException if the server version is unsupported.
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(ServerVersion serverVersion, String teamName, FS_ClientboundCreateOrUpdateTeamPacket.RemoveTeam removeTeam) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet to create or update a team with the specified name and removal flag.
|
||||
*
|
||||
* @param teamName the name of the team to create or update
|
||||
* @param removeTeam the flag indicating whether to remove the team
|
||||
* @return a packet for creating or updating the team
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(String teamName, FS_ClientboundCreateOrUpdateTeamPacket.RemoveTeam removeTeam) {
|
||||
return createCreateOrUpdateTeamPacket(ServerVersion.getCurrentVersion(), teamName, removeTeam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of FS_ClientboundCreateOrUpdateTeamPacket based on the provided server version.
|
||||
*
|
||||
* @param serverVersion The server version for which the packet should be created.
|
||||
* @param teamName The name of the team that is being created or updated.
|
||||
* @param updateTeam The update team details which contain information about the team.
|
||||
* @return A new instance of FS_ClientboundCreateOrUpdateTeamPacket tailored for the specified server version.
|
||||
* @throws IllegalArgumentException If the provided server version is not supported.
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(ServerVersion serverVersion, String teamName, FS_ClientboundCreateOrUpdateTeamPacket.UpdateTeam updateTeam) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FS_ClientboundCreateOrUpdateTeamPacket for creating or updating a team.
|
||||
*
|
||||
* @param teamName the name of the team to be created or updated
|
||||
* @param updateTeam the update information for the team
|
||||
* @return a new instance of FS_ClientboundCreateOrUpdateTeamPacket
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(String teamName, FS_ClientboundCreateOrUpdateTeamPacket.UpdateTeam updateTeam) {
|
||||
return createCreateOrUpdateTeamPacket(ServerVersion.getCurrentVersion(), teamName, updateTeam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of FS_ClientboundCreateOrUpdateTeamPacket based on the given server version, team name, and addEntity parameters.
|
||||
*
|
||||
* @param serverVersion the version of the server for which the packet will be created
|
||||
* @param teamName the name of the team to be created or updated
|
||||
* @param addEntity the add entity information needed for packet creation
|
||||
* @return an instance of FS_ClientboundCreateOrUpdateTeamPacket appropriate for the specified server version
|
||||
* @throws IllegalArgumentException if the server version is not supported
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(ServerVersion serverVersion, String teamName, FS_ClientboundCreateOrUpdateTeamPacket.AddEntity addEntity) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet for creating or updating a team with the specified name and entity.
|
||||
*
|
||||
* @param teamName the name of the team to create or update
|
||||
* @param addEntity the entity representing the addition details for the team
|
||||
* @return the packet representing the create or update operation on the team
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(String teamName, FS_ClientboundCreateOrUpdateTeamPacket.AddEntity addEntity) {
|
||||
return createCreateOrUpdateTeamPacket(ServerVersion.getCurrentVersion(), teamName, addEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of FS_ClientboundCreateOrUpdateTeamPacket based on the server version.
|
||||
*
|
||||
* @param serverVersion The version of the server.
|
||||
* @param teamName The name of the team to create or update.
|
||||
* @param removeEntity The entity removal configuration for the packet.
|
||||
* @return A new instance of FS_ClientboundCreateOrUpdateTeamPacket for the specified server version.
|
||||
* @throws IllegalArgumentException If the server version is unsupported.
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(ServerVersion serverVersion, String teamName, FS_ClientboundCreateOrUpdateTeamPacket.RemoveEntity removeEntity) {
|
||||
switch (serverVersion) {
|
||||
case v1_21_4 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_4.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity);
|
||||
}
|
||||
case v1_21_3 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_21_3.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity);
|
||||
}
|
||||
case v1_20_5, v1_20_6, v1_21, v1_21_1 -> {
|
||||
return new de.oliver.fancysitula.versions.v1_20_6.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported server version: " + serverVersion.getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet for creating or updating a team with the specified name and entity removal configuration.
|
||||
*
|
||||
* @param teamName the name of the team to create or update
|
||||
* @param removeEntity the entity removal configuration for the team
|
||||
* @return the packet for creating or updating the team
|
||||
*/
|
||||
public FS_ClientboundCreateOrUpdateTeamPacket createCreateOrUpdateTeamPacket(String teamName, FS_ClientboundCreateOrUpdateTeamPacket.RemoveEntity removeEntity) {
|
||||
return createCreateOrUpdateTeamPacket(ServerVersion.getCurrentVersion(), teamName, removeEntity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package de.oliver.fancysitula.factories;
|
||||
|
||||
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
|
||||
import de.oliver.fancysitula.api.packets.FS_ClientboundCreateOrUpdateTeamPacket;
|
||||
import de.oliver.fancysitula.api.teams.FS_Team;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TeamFactory {
|
||||
|
||||
public void createTeamFor(FS_RealPlayer player, FS_Team team) {
|
||||
FS_ClientboundCreateOrUpdateTeamPacket packet = FancySitula.PACKET_FACTORY.createCreateOrUpdateTeamPacket(
|
||||
team.getTeamName(),
|
||||
new FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam(
|
||||
team.getDisplayName(),
|
||||
team.isAllowFriendlyFire(),
|
||||
team.isCanSeeFriendlyInvisibles(),
|
||||
team.getNameTagVisibility(),
|
||||
team.getCollisionRule(),
|
||||
team.getColor(),
|
||||
team.getPrefix(),
|
||||
team.getSuffix(),
|
||||
team.getEntities()
|
||||
)
|
||||
);
|
||||
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
public void removeTeamFor(FS_RealPlayer player, FS_Team team) {
|
||||
FS_ClientboundCreateOrUpdateTeamPacket packet = FancySitula.PACKET_FACTORY.createCreateOrUpdateTeamPacket(
|
||||
team.getTeamName(),
|
||||
new FS_ClientboundCreateOrUpdateTeamPacket.RemoveTeam()
|
||||
);
|
||||
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the team for the player. But does not add or remove entities.
|
||||
*/
|
||||
public void updateTeamFor(FS_RealPlayer player, FS_Team team) {
|
||||
FS_ClientboundCreateOrUpdateTeamPacket packet = FancySitula.PACKET_FACTORY.createCreateOrUpdateTeamPacket(
|
||||
team.getTeamName(),
|
||||
new FS_ClientboundCreateOrUpdateTeamPacket.UpdateTeam(
|
||||
team.getDisplayName(),
|
||||
team.isAllowFriendlyFire(),
|
||||
team.isCanSeeFriendlyInvisibles(),
|
||||
team.getNameTagVisibility(),
|
||||
team.getCollisionRule(),
|
||||
team.getColor(),
|
||||
team.getPrefix(),
|
||||
team.getSuffix()
|
||||
)
|
||||
);
|
||||
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
public void addEntitiesToTeamFor(FS_RealPlayer player, FS_Team team, List<String> entities) {
|
||||
FS_ClientboundCreateOrUpdateTeamPacket packet = FancySitula.PACKET_FACTORY.createCreateOrUpdateTeamPacket(
|
||||
team.getTeamName(),
|
||||
new FS_ClientboundCreateOrUpdateTeamPacket.AddEntity(entities)
|
||||
);
|
||||
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
|
||||
public void removeEntitiesFromTeamFor(FS_RealPlayer player, FS_Team team, List<String> entities) {
|
||||
FS_ClientboundCreateOrUpdateTeamPacket packet = FancySitula.PACKET_FACTORY.createCreateOrUpdateTeamPacket(
|
||||
team.getTeamName(),
|
||||
new FS_ClientboundCreateOrUpdateTeamPacket.RemoveEntity(entities)
|
||||
);
|
||||
|
||||
player.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
BIN
libraries/packets/fancysitula_title.png
Normal file
BIN
libraries/packets/fancysitula_title.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
2
libraries/packets/gradle.properties
Normal file
2
libraries/packets/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
minecraftVersion=1.21.3
|
||||
fancyLoggerVersion=0.0.4
|
||||
23
libraries/packets/implementations/1_20_6/build.gradle.kts
Normal file
23
libraries/packets/implementations/1_20_6/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("io.papermc.paperweight.userdev")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.20.6"
|
||||
|
||||
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("$minecraftVersion-R0.1-SNAPSHOT")
|
||||
compileOnly(project(":libraries:packets:api"))
|
||||
|
||||
testImplementation(project(":libraries:packets:api"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2")
|
||||
}
|
||||
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user