mirror of
https://github.com/FancyInnovations/FancyPlugins.git
synced 2025-12-06 07:43:36 +00:00
Add FancyVisuals plugin
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
fancyhologramsVersion=2.4.2
|
fancyhologramsVersion=2.4.2
|
||||||
|
fancyvisualsVersion=0.0.1
|
||||||
fancylibVersion=36
|
fancylibVersion=36
|
||||||
fancysitulaVersion=0.0.13
|
fancysitulaVersion=0.0.13
|
||||||
jdbVersion=1.0.0
|
jdbVersion=1.0.0
|
||||||
|
|||||||
120
plugins/fancyvisuals/.gitignore
vendored
Normal file
120
plugins/fancyvisuals/.gitignore
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
run/
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
51
plugins/fancyvisuals/README.md
Normal file
51
plugins/fancyvisuals/README.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# FancyVisuals
|
||||||
|
|
||||||
|
**Do not use this plugin in production! It is still in development and may contain bugs and unfinished features.**
|
||||||
|
|
||||||
|
This is a plugin to customise most visual components of your minecraft server. This includes the scoreboard, tablist,
|
||||||
|
bossbar, actionbar, title, chat and nametags. This plugin is highly customisable and can be used to create a unique
|
||||||
|
experience for your players.
|
||||||
|
This plugin is packet based (powered by FancySitula), meaning it is blazing fast and has no impact on server
|
||||||
|
performance. You can use placeholders by PlaceholderAPI anywhere in the plugin.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
The plugin is divided into multiple modules, each of which can be configured individually.
|
||||||
|
|
||||||
|
### Nametags
|
||||||
|
|
||||||
|
- With the nametags module, you can customise the nametags (text above the player's head) of players
|
||||||
|
- The nametags are implemented using display entities
|
||||||
|
- The nametags can have multiple lines and a configurable background
|
||||||
|
- You can use MiniMessage for coloring and formatting
|
||||||
|
- Placeholders by PlaceholderAPI are supported
|
||||||
|
|
||||||
|
### Scoreboard
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
### Tablist
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
### Bossbar
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
### Actionbar
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
### Title & Subtitle
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
### Chat
|
||||||
|
|
||||||
|
Comming soon
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Paper **1.20.5** - **1.21.4** with **Java 21** (or higher) is required.
|
||||||
|
|
||||||
|
**Spigot** is **not** supported.
|
||||||
57
plugins/fancyvisuals/api/build.gradle.kts
Normal file
57
plugins/fancyvisuals/api/build.gradle.kts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
id("maven-publish")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = "de.oliver"
|
||||||
|
artifactId = "FancyVisuals"
|
||||||
|
version = findProperty("fancyvisualsVersion") as String
|
||||||
|
from(project.components["java"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
}
|
||||||
|
|
||||||
|
compileJava {
|
||||||
|
options.encoding = Charsets.UTF_8.name()
|
||||||
|
options.release = 21
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package de.oliver.fancyvisuals.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different contexts in which operations can be performed.
|
||||||
|
* Each context is associated with a specific priority level that indicates its specificity.
|
||||||
|
*/
|
||||||
|
public enum Context {
|
||||||
|
|
||||||
|
SERVER(1),
|
||||||
|
WORLD(2),
|
||||||
|
GROUP(3),
|
||||||
|
PLAYER(4),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int priority;
|
||||||
|
|
||||||
|
Context(int priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the priority level associated with this context.
|
||||||
|
* Higher priority levels indicate more specific contexts.
|
||||||
|
*
|
||||||
|
* @return the priority level as an integer
|
||||||
|
*/
|
||||||
|
public int getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package de.oliver.fancyvisuals.api;
|
||||||
|
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagRepository;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public interface FancyVisualsAPI {
|
||||||
|
|
||||||
|
JavaPlugin getPlugin();
|
||||||
|
|
||||||
|
NametagRepository getNametagRepository();
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package de.oliver.fancyvisuals.api.nametags;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record Nametag(
|
||||||
|
@SerializedName("text_lines")
|
||||||
|
@NotNull List<String> textLines,
|
||||||
|
|
||||||
|
@SerializedName("background_color")
|
||||||
|
@NotNull String backgroundColor,
|
||||||
|
|
||||||
|
@SerializedName("text_shadow")
|
||||||
|
@NotNull Boolean textShadow,
|
||||||
|
|
||||||
|
@SerializedName("text_alignment")
|
||||||
|
@NotNull TextAlignment textAlignment
|
||||||
|
) {
|
||||||
|
|
||||||
|
public enum TextAlignment {
|
||||||
|
@SerializedName("left")
|
||||||
|
LEFT,
|
||||||
|
|
||||||
|
@SerializedName("right")
|
||||||
|
RIGHT,
|
||||||
|
|
||||||
|
@SerializedName("center")
|
||||||
|
CENTER
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package de.oliver.fancyvisuals.api.nametags;
|
||||||
|
|
||||||
|
import de.oliver.fancyvisuals.api.Context;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code NametagRepository} interface provides methods for retrieving {@code NametagStore} and {@code Nametag}
|
||||||
|
* instances based on different contexts.
|
||||||
|
*/
|
||||||
|
public interface NametagRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default {@code Nametag} instance used when no specific nametag is found for a given context or player.
|
||||||
|
*/
|
||||||
|
Nametag DEFAULT_NAMETAG = new Nametag(
|
||||||
|
List.of("<gradient:#8c0010:#803c12>%player_name%</gradient>"),
|
||||||
|
"#000000",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the {@code NametagStore} associated with the given context.
|
||||||
|
*
|
||||||
|
* @param context the context for which the store is to be retrieved. This determines if the store is for SERVER, WORLD, GROUP, or PLAYER.
|
||||||
|
* @return the NametagStore associated with the provided context.
|
||||||
|
*/
|
||||||
|
@NotNull NametagStore getStore(@NotNull Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the {@code Nametag} associated with the specified {@code id} within the given {@code context}.
|
||||||
|
*
|
||||||
|
* @param context the context for which the nametag is to be retrieved. This determines if the nametag is for SERVER, WORLD, GROUP, or PLAYER.
|
||||||
|
* @param id the unique identifier for the nametag.
|
||||||
|
* @return the Nametag associated with the given id; may return null if no such nametag is found within the specified context.
|
||||||
|
*/
|
||||||
|
default @Nullable Nametag getNametag(@NotNull Context context, @NotNull String id) {
|
||||||
|
return getStore(context).getNametag(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the appropriate {@code Nametag} for the specified {@code Player} based on various contexts.
|
||||||
|
* The method checks the PLAYER, GROUP, WORLD, and SERVER contexts in order, returning the first matching nametag found.
|
||||||
|
* If no matching nametag is found in any context, a default nametag is returned.
|
||||||
|
*
|
||||||
|
* @param player the Player for whom the nametag is being retrieved
|
||||||
|
* @return the Nametag associated with the player, or a default nametag if no specific nametag is found
|
||||||
|
*/
|
||||||
|
@NotNull Nametag getNametagForPlayer(@NotNull Player player);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package de.oliver.fancyvisuals.api.nametags;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code NametagStore} interface defines operations for storing, retrieving, and managing {@code Nametag} objects
|
||||||
|
* associated with unique identifiers.
|
||||||
|
*/
|
||||||
|
public interface NametagStore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the specified {@code Nametag} with the provided {@code id} in the store.
|
||||||
|
*
|
||||||
|
* @param id the unique identifier for the nametag.
|
||||||
|
* @param nametag the Nametag object to be associated with the specified id.
|
||||||
|
*/
|
||||||
|
void setNametag(@NotNull String id, @NotNull Nametag nametag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the {@code Nametag} associated with the specified {@code id}.
|
||||||
|
*
|
||||||
|
* @param id the unique identifier for the nametag.
|
||||||
|
* @return the Nametag associated with the given id; may return null if no such nametag is found.
|
||||||
|
*/
|
||||||
|
@Nullable Nametag getNametag(@NotNull String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the {@code Nametag} associated with the specified {@code id} from the store.
|
||||||
|
*
|
||||||
|
* @param id the unique identifier for the nametag to be removed.
|
||||||
|
*/
|
||||||
|
void removeNametag(@NotNull String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of all the Nametags in the store.
|
||||||
|
*
|
||||||
|
* @return a list of Nametag objects; the list may be empty if no nametags are present in the store.
|
||||||
|
*/
|
||||||
|
@NotNull List<Nametag> getNametags();
|
||||||
|
|
||||||
|
}
|
||||||
131
plugins/fancyvisuals/build.gradle.kts
Normal file
131
plugins/fancyvisuals/build.gradle.kts
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import net.minecrell.pluginyml.paper.PaperPluginDescription
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
|
||||||
|
id("xyz.jpenilla.run-paper")
|
||||||
|
id("com.gradleup.shadow")
|
||||||
|
id("net.minecrell.plugin-yml.paper")
|
||||||
|
}
|
||||||
|
|
||||||
|
runPaper.folia.registerTask()
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
group = "de.oliver"
|
||||||
|
version = findProperty("fancyvisualsVersion") as String
|
||||||
|
description = "Simple, lightweight and fast visual plugin using packets"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
maven(url = "https://repo.papermc.io/repository/maven-public/")
|
||||||
|
maven(url = "https://repo.fancyplugins.de/releases")
|
||||||
|
maven(url = "https://repo.lushplugins.org/releases")
|
||||||
|
maven(url = "https://jitpack.io")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly("io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
|
implementation(project(":plugins:fancyvisuals:api"))
|
||||||
|
|
||||||
|
compileOnly("de.oliver:FancyLib:33") // loaded in FancyVisualLoader
|
||||||
|
compileOnly("de.oliver:FancySitula:0.0.13") // loaded in FancyVisualLoader
|
||||||
|
compileOnly("de.oliver.FancyAnalytics:api:0.0.8") // loaded in FancyVisualLoader
|
||||||
|
compileOnly("de.oliver.FancyAnalytics:logger:0.0.5") // loaded in FancyVisualLoader
|
||||||
|
|
||||||
|
implementation("org.lushplugins:ChatColorHandler:4.0.0")
|
||||||
|
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")
|
||||||
|
|
||||||
|
// commands
|
||||||
|
implementation("org.incendo:cloud-core:2.0.0")
|
||||||
|
implementation("org.incendo:cloud-paper:2.0.0-beta.10")
|
||||||
|
implementation("org.incendo:cloud-annotations:2.0.0")
|
||||||
|
annotationProcessor("org.incendo:cloud-annotations:2.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
paper {
|
||||||
|
main = "de.oliver.fancyvisuals.FancyVisuals"
|
||||||
|
bootstrapper = "de.oliver.fancyvisuals.loaders.FancyVisualsBootstrapper"
|
||||||
|
loader = "de.oliver.fancyvisuals.loaders.FancyVisualsLoader"
|
||||||
|
foliaSupported = true
|
||||||
|
version = findProperty("fancyvisualsVersion") as String
|
||||||
|
description = "Simple, lightweight and fast visuals plugin using packets"
|
||||||
|
apiVersion = "1.19"
|
||||||
|
serverDependencies {
|
||||||
|
register("PlaceholderAPI") {
|
||||||
|
required = false
|
||||||
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
|
}
|
||||||
|
register("MiniPlaceholders") {
|
||||||
|
required = false
|
||||||
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
|
}
|
||||||
|
register("LuckPerms") {
|
||||||
|
required = false
|
||||||
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
|
}
|
||||||
|
register("PermissionsEx") {
|
||||||
|
required = false
|
||||||
|
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
minecraftVersion("1.21.4")
|
||||||
|
|
||||||
|
downloadPlugins {
|
||||||
|
hangar("ViaVersion", "5.0.3")
|
||||||
|
hangar("ViaBackwards", "5.0.3")
|
||||||
|
hangar("PlaceholderAPI", "2.11.6")
|
||||||
|
// modrinth("multiverse-core", "4.3.11")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
archiveClassifier.set("")
|
||||||
|
dependsOn(":plugins:fancyvisuals:api:jar")
|
||||||
|
}
|
||||||
|
|
||||||
|
compileJava {
|
||||||
|
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||||
|
options.release = 21
|
||||||
|
// For cloud-annotations, see https://cloud.incendo.org/annotations/#command-components
|
||||||
|
options.compilerArgs.add("-parameters")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
val props = mapOf(
|
||||||
|
"description" to project.description,
|
||||||
|
"version" to project.version,
|
||||||
|
"hash" to getCurrentCommitHash(),
|
||||||
|
)
|
||||||
|
|
||||||
|
inputs.properties(props)
|
||||||
|
|
||||||
|
filesMatching("paper-plugin.yml") {
|
||||||
|
expand(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
filesMatching("version.yml") {
|
||||||
|
expand(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCurrentCommitHash(): String {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package de.oliver.fancyvisuals;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import de.oliver.fancyanalytics.logger.ExtendedFancyLogger;
|
||||||
|
import de.oliver.fancyanalytics.logger.LogLevel;
|
||||||
|
import de.oliver.fancylib.FancyLib;
|
||||||
|
import de.oliver.fancysitula.api.IFancySitula;
|
||||||
|
import de.oliver.fancyvisuals.analytics.AnalyticsManager;
|
||||||
|
import de.oliver.fancyvisuals.api.FancyVisualsAPI;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagRepository;
|
||||||
|
import de.oliver.fancyvisuals.config.FancyVisualsConfig;
|
||||||
|
import de.oliver.fancyvisuals.config.NametagConfig;
|
||||||
|
import de.oliver.fancyvisuals.nametags.listeners.NametagListeners;
|
||||||
|
import de.oliver.fancyvisuals.nametags.store.JsonNametagRepository;
|
||||||
|
import de.oliver.fancyvisuals.nametags.visibility.PlayerNametagScheduler;
|
||||||
|
import de.oliver.fancyvisuals.playerConfig.JsonPlayerConfigStore;
|
||||||
|
import de.oliver.fancyvisuals.utils.VaultHelper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public final class FancyVisuals extends JavaPlugin implements FancyVisualsAPI {
|
||||||
|
|
||||||
|
private static final ExtendedFancyLogger logger = IFancySitula.LOGGER;
|
||||||
|
private static FancyVisuals instance;
|
||||||
|
private final AnalyticsManager analyticsManager;
|
||||||
|
private final FancyVisualsConfig fancyVisualsConfig;
|
||||||
|
private final NametagConfig nametagConfig;
|
||||||
|
private ExecutorService workerExecutor;
|
||||||
|
|
||||||
|
private JsonPlayerConfigStore playerConfigStore;
|
||||||
|
|
||||||
|
private NametagRepository nametagRepository;
|
||||||
|
private PlayerNametagScheduler nametagScheduler;
|
||||||
|
|
||||||
|
public FancyVisuals() {
|
||||||
|
instance = this;
|
||||||
|
this.analyticsManager = new AnalyticsManager("34c5a33d-0ff0-48b1-8b1c-53620a690c6e", "981ce185-c961-4618-bf61-71a8ed6c3962", "SxIBSDA2MDVkMGUwOTk3MzQ3NjCmP0UU");
|
||||||
|
this.fancyVisualsConfig = new FancyVisualsConfig();
|
||||||
|
this.nametagConfig = new NametagConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FancyVisuals get() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull ExtendedFancyLogger getFancyLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
FancyLib fancyLib = new FancyLib(this);
|
||||||
|
IFancySitula.LOGGER.setCurrentLevel(LogLevel.DEBUG);
|
||||||
|
|
||||||
|
// config
|
||||||
|
fancyVisualsConfig.load();
|
||||||
|
nametagConfig.load();
|
||||||
|
|
||||||
|
// worker executor
|
||||||
|
this.workerExecutor = Executors.newFixedThreadPool(
|
||||||
|
fancyVisualsConfig.getAmountWorkerThreads(),
|
||||||
|
new ThreadFactoryBuilder()
|
||||||
|
.setNameFormat("FancyVisualsWorker-%d")
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Player config
|
||||||
|
playerConfigStore = new JsonPlayerConfigStore();
|
||||||
|
|
||||||
|
// Nametags
|
||||||
|
nametagRepository = new JsonNametagRepository();
|
||||||
|
nametagScheduler = new PlayerNametagScheduler(workerExecutor, nametagConfig.getDistributionBucketSize());
|
||||||
|
|
||||||
|
// analytics
|
||||||
|
analyticsManager.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||||
|
|
||||||
|
// Vault
|
||||||
|
VaultHelper.loadVault();
|
||||||
|
|
||||||
|
// Nametags
|
||||||
|
nametagScheduler.init();
|
||||||
|
pluginManager.registerEvents(new NametagListeners(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaPlugin getPlugin() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonPlayerConfigStore getPlayerConfigStore() {
|
||||||
|
return playerConfigStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NametagRepository getNametagRepository() {
|
||||||
|
return nametagRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerNametagScheduler getNametagScheduler() {
|
||||||
|
return nametagScheduler;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package de.oliver.fancyvisuals.analytics;
|
||||||
|
|
||||||
|
import de.oliver.fancyanalytics.api.FancyAnalyticsAPI;
|
||||||
|
import de.oliver.fancyanalytics.api.MetricSupplier;
|
||||||
|
import de.oliver.fancyvisuals.FancyVisuals;
|
||||||
|
import de.oliver.fancyvisuals.api.Context;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagRepository;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class AnalyticsManager {
|
||||||
|
|
||||||
|
private final FancyAnalyticsAPI fa;
|
||||||
|
|
||||||
|
public AnalyticsManager(String userId, String projectId, String apiKey) {
|
||||||
|
this.fa = new FancyAnalyticsAPI(userId, projectId, apiKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
fa.registerDefaultPluginMetrics(FancyVisuals.get());
|
||||||
|
fa.registerLogger(FancyVisuals.get().getLogger());
|
||||||
|
fa.registerLogger(Logger.getGlobal());
|
||||||
|
|
||||||
|
registerNametagMetrics();
|
||||||
|
|
||||||
|
fa.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerNametagMetrics() {
|
||||||
|
NametagRepository repo = FancyVisuals.get().getNametagRepository();
|
||||||
|
|
||||||
|
fa.registerNumberMetric(new MetricSupplier<>("nametag_count_total", () -> {
|
||||||
|
double count = 0;
|
||||||
|
for (Context ctx : Context.values()) {
|
||||||
|
count += repo.getStore(ctx).getNametags().size();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}));
|
||||||
|
fa.registerNumberMetric(new MetricSupplier<>("nametag_count_player", () -> (double) repo.getStore(Context.PLAYER).getNametags().size()));
|
||||||
|
fa.registerNumberMetric(new MetricSupplier<>("nametag_count_group", () -> (double) repo.getStore(Context.GROUP).getNametags().size()));
|
||||||
|
fa.registerNumberMetric(new MetricSupplier<>("nametag_count_world", () -> (double) repo.getStore(Context.WORLD).getNametags().size()));
|
||||||
|
fa.registerNumberMetric(new MetricSupplier<>("nametag_count_server", () -> (double) repo.getStore(Context.SERVER).getNametags().size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package de.oliver.fancyvisuals.config;
|
||||||
|
|
||||||
|
public class FancyVisualsConfig {
|
||||||
|
|
||||||
|
private int amountWorkerThreads;
|
||||||
|
|
||||||
|
public FancyVisualsConfig() {
|
||||||
|
this.amountWorkerThreads = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmountWorkerThreads() {
|
||||||
|
return amountWorkerThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.oliver.fancyvisuals.config;
|
||||||
|
|
||||||
|
public class NametagConfig {
|
||||||
|
|
||||||
|
private int distributionBucketSize;
|
||||||
|
|
||||||
|
public NametagConfig() {
|
||||||
|
distributionBucketSize = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the size of the distribution bucket configured.
|
||||||
|
*
|
||||||
|
* @return The size of the distribution bucket.
|
||||||
|
*/
|
||||||
|
public int getDistributionBucketSize() {
|
||||||
|
return distributionBucketSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package de.oliver.fancyvisuals.loaders;
|
||||||
|
|
||||||
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
|
||||||
|
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class FancyVisualsBootstrapper implements PluginBootstrap {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bootstrap(@NotNull BootstrapContext context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package de.oliver.fancyvisuals.loaders;
|
||||||
|
|
||||||
|
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
|
||||||
|
import io.papermc.paper.plugin.loader.PluginLoader;
|
||||||
|
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
|
||||||
|
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||||
|
import org.eclipse.aether.graph.Dependency;
|
||||||
|
import org.eclipse.aether.repository.RemoteRepository;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class FancyVisualsLoader implements PluginLoader {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void classloader(@NotNull PluginClasspathBuilder classpathBuilder) {
|
||||||
|
|
||||||
|
MavenLibraryResolver resolver = new MavenLibraryResolver();
|
||||||
|
resolver.addRepository(new RemoteRepository.Builder("fancyplugins", "default", "https://repo.fancyplugins.de/releases").build());
|
||||||
|
// resolver.addRepository(new RemoteRepository.Builder("mavencentral", "default", "https://repo1.maven.org/maven2/").build());
|
||||||
|
resolver.addDependency(new Dependency(new DefaultArtifact("de.oliver:FancyLib:33"), "compile"));
|
||||||
|
resolver.addDependency(new Dependency(new DefaultArtifact("de.oliver:FancySitula:0.0.13"), "compile"));
|
||||||
|
resolver.addDependency(new Dependency(new DefaultArtifact("de.oliver.FancyAnalytics:api:0.0.5"), "compile"));
|
||||||
|
resolver.addDependency(new Dependency(new DefaultArtifact("de.oliver.FancyAnalytics:logger:0.0.5"), "compile"));
|
||||||
|
|
||||||
|
classpathBuilder.addLibrary(resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.fake;
|
||||||
|
|
||||||
|
import de.oliver.fancyvisuals.api.Context;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagRepository;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagStore;
|
||||||
|
import de.oliver.fancyvisuals.utils.VaultHelper;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class FakeNametagRepository implements NametagRepository {
|
||||||
|
|
||||||
|
private final Map<Context, NametagStore> stores;
|
||||||
|
|
||||||
|
public FakeNametagRepository() {
|
||||||
|
this.stores = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
for (Context ctx : Context.values()) {
|
||||||
|
stores.put(ctx, new FakeNametagStore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull NametagStore getStore(@NotNull Context context) {
|
||||||
|
return stores.get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Nametag getNametagForPlayer(@NotNull Player player) {
|
||||||
|
Nametag nametag = getNametag(Context.PLAYER, player.getUniqueId().toString());
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VaultHelper.isVaultLoaded()) {
|
||||||
|
nametag = getNametag(Context.GROUP, VaultHelper.getPermission().getPrimaryGroup(player));
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nametag = getNametag(Context.WORLD, player.getWorld().getName());
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
nametag = getNametag(Context.SERVER, "global");
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_NAMETAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.fake;
|
||||||
|
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagStore;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class FakeNametagStore implements NametagStore {
|
||||||
|
|
||||||
|
private final Map<String, Nametag> nametags;
|
||||||
|
|
||||||
|
public FakeNametagStore() {
|
||||||
|
this.nametags = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNametag(@NotNull String id, @NotNull Nametag nametag) {
|
||||||
|
nametags.put(id, nametag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Nametag getNametag(@NotNull String id) {
|
||||||
|
return nametags.getOrDefault(id, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNametag(@NotNull String id) {
|
||||||
|
nametags.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Nametag> getNametags() {
|
||||||
|
return List.copyOf(nametags.values());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.listeners;
|
||||||
|
|
||||||
|
import de.oliver.fancyvisuals.FancyVisuals;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.nametags.visibility.PlayerNametag;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
public class NametagListeners implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
Nametag nametag = FancyVisuals.get().getNametagRepository().getNametagForPlayer(player);
|
||||||
|
PlayerNametag playerNametag = new PlayerNametag(nametag, player);
|
||||||
|
FancyVisuals.get().getNametagScheduler().add(playerNametag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerWorldChange(PlayerChangedWorldEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
Nametag nametag = FancyVisuals.get().getNametagRepository().getNametagForPlayer(player);
|
||||||
|
PlayerNametag playerNametag = new PlayerNametag(nametag, player);
|
||||||
|
FancyVisuals.get().getNametagScheduler().add(playerNametag);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.store;
|
||||||
|
|
||||||
|
import de.oliver.fancylib.jdb.JDB;
|
||||||
|
import de.oliver.fancyvisuals.api.Context;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagRepository;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagStore;
|
||||||
|
import de.oliver.fancyvisuals.utils.VaultHelper;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class JsonNametagRepository implements NametagRepository {
|
||||||
|
|
||||||
|
private static final String BASE_PATH = "plugins/FancyVisuals/data/nametags/";
|
||||||
|
private final JDB jdb;
|
||||||
|
private final Map<Context, NametagStore> stores;
|
||||||
|
|
||||||
|
public JsonNametagRepository() {
|
||||||
|
this.jdb = new JDB(BASE_PATH);
|
||||||
|
stores = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
for (Context ctx : Context.values()) {
|
||||||
|
stores.put(ctx, new JsonNametagStore(jdb, ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
initialConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull NametagStore getStore(@NotNull Context context) {
|
||||||
|
return stores.get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Nametag getNametagForPlayer(@NotNull Player player) {
|
||||||
|
Nametag nametag = getNametag(Context.PLAYER, player.getUniqueId().toString());
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VaultHelper.isVaultLoaded()) {
|
||||||
|
nametag = getNametag(Context.GROUP, VaultHelper.getPermission().getPrimaryGroup(player));
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nametag = getNametag(Context.WORLD, player.getWorld().getName());
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
nametag = getNametag(Context.SERVER, "global");
|
||||||
|
if (nametag != null) {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_NAMETAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialConfig() {
|
||||||
|
File baseDir = new File(BASE_PATH);
|
||||||
|
if (baseDir.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NametagStore serverStore = getStore(Context.SERVER);
|
||||||
|
serverStore.setNametag("global", DEFAULT_NAMETAG);
|
||||||
|
|
||||||
|
NametagStore worldStore = getStore(Context.WORLD);
|
||||||
|
worldStore.setNametag("world", new Nametag(
|
||||||
|
List.of("Overworld", "%player%"),
|
||||||
|
"#C800AA00",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
worldStore.setNametag("world_nether", new Nametag(
|
||||||
|
List.of("Nether", "%player%"),
|
||||||
|
"#C8AA0000",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
worldStore.setNametag("world_the_end", new Nametag(
|
||||||
|
List.of("The End", "%player%"),
|
||||||
|
"#C80000AA",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
|
||||||
|
NametagStore groupStore = getStore(Context.GROUP);
|
||||||
|
groupStore.setNametag("admin", new Nametag(
|
||||||
|
List.of("Admin", "%player%"),
|
||||||
|
"#C8FF0000",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
groupStore.setNametag("moderator", new Nametag(
|
||||||
|
List.of("Mod", "%player%"),
|
||||||
|
"#C8FFAA00",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
|
||||||
|
NametagStore playerStore = getStore(Context.PLAYER);
|
||||||
|
playerStore.setNametag(UUID.randomUUID().toString(), new Nametag(
|
||||||
|
List.of("Player", "%player%"),
|
||||||
|
"#C800FF00",
|
||||||
|
true,
|
||||||
|
Nametag.TextAlignment.CENTER
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.store;
|
||||||
|
|
||||||
|
import de.oliver.fancylib.jdb.JDB;
|
||||||
|
import de.oliver.fancyvisuals.FancyVisuals;
|
||||||
|
import de.oliver.fancyvisuals.api.Context;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.NametagStore;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class JsonNametagStore implements NametagStore {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
private final JDB jdb;
|
||||||
|
|
||||||
|
public JsonNametagStore(JDB jdb, Context context) {
|
||||||
|
this.jdb = jdb;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNametag(@NotNull String id, @NotNull Nametag nametag) {
|
||||||
|
try {
|
||||||
|
jdb.set(context.getName() + "/" + id, nametag);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to set nametag for id " + id);
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Nametag getNametag(@NotNull String id) {
|
||||||
|
Nametag nametag = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
nametag = jdb.get(context.getName() + "/" + id, Nametag.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to get nametag for id " + id);
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNametag(@NotNull String id) {
|
||||||
|
jdb.delete(context.getName() + "/" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Nametag> getNametags() {
|
||||||
|
List<Nametag> nametags = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
jdb.getAll(context.getName(), Nametag.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to get all nametags");
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nametags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.visibility;
|
||||||
|
|
||||||
|
import de.oliver.fancysitula.api.entities.FS_Display;
|
||||||
|
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
|
||||||
|
import de.oliver.fancysitula.api.entities.FS_TextDisplay;
|
||||||
|
import de.oliver.fancysitula.factories.FancySitula;
|
||||||
|
import de.oliver.fancyvisuals.FancyVisuals;
|
||||||
|
import de.oliver.fancyvisuals.api.nametags.Nametag;
|
||||||
|
import de.oliver.fancyvisuals.playerConfig.PlayerConfig;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.lushplugins.chatcolorhandler.ModernChatColorHandler;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class PlayerNametag {
|
||||||
|
|
||||||
|
private final Nametag nametag;
|
||||||
|
private final Player player;
|
||||||
|
private final Set<UUID> viewers;
|
||||||
|
private FS_TextDisplay fsTextDisplay;
|
||||||
|
|
||||||
|
public PlayerNametag(Nametag nametag, Player player) {
|
||||||
|
this.nametag = nametag;
|
||||||
|
this.player = player;
|
||||||
|
this.viewers = new HashSet<>();
|
||||||
|
this.fsTextDisplay = new FS_TextDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVisibilityForAll() {
|
||||||
|
cleanViewers();
|
||||||
|
|
||||||
|
for (Player viewer : Bukkit.getOnlinePlayers()) {
|
||||||
|
boolean should = shouldBeVisibleTo(viewer);
|
||||||
|
boolean is = isVisibleTo(viewer);
|
||||||
|
|
||||||
|
if (should && !is) {
|
||||||
|
showTo(viewer);
|
||||||
|
} else if (!should && is) {
|
||||||
|
hideFrom(viewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldBeVisibleTo(Player viewer) {
|
||||||
|
if (!player.isOnline()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!viewer.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getUniqueId().equals(viewer.getUniqueId())) {
|
||||||
|
PlayerConfig playerConfig = FancyVisuals.get().getPlayerConfigStore().getPlayerConfig(player.getUniqueId());
|
||||||
|
if (!playerConfig.showOwnNametag()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean dead = player.isDead();
|
||||||
|
if (dead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean inDistance = isInDistance(viewer.getLocation(), player.getLocation(), 24);
|
||||||
|
if (!inDistance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showTo(Player viewer) {
|
||||||
|
viewers.add(viewer.getUniqueId());
|
||||||
|
|
||||||
|
FS_RealPlayer fsViewer = new FS_RealPlayer(viewer);
|
||||||
|
FancySitula.ENTITY_FACTORY.spawnEntityFor(fsViewer, fsTextDisplay);
|
||||||
|
updateFor(viewer);
|
||||||
|
letDisplayRidePlayer(viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideFrom(Player viewer) {
|
||||||
|
viewers.remove(viewer.getUniqueId());
|
||||||
|
|
||||||
|
FS_RealPlayer fsViewer = new FS_RealPlayer(viewer);
|
||||||
|
FancySitula.ENTITY_FACTORY.despawnEntityFor(fsViewer, fsTextDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateFor(Player viewer) {
|
||||||
|
fsTextDisplay.setTranslation(new Vector3f(0, 0.2f, 0));
|
||||||
|
|
||||||
|
fsTextDisplay.setBillboard(FS_Display.Billboard.CENTER);
|
||||||
|
|
||||||
|
Color bgColor = Color.fromARGB((int) Long.parseLong(nametag.backgroundColor().substring(1), 16));
|
||||||
|
fsTextDisplay.setBackground(bgColor.asARGB());
|
||||||
|
|
||||||
|
fsTextDisplay.setStyleFlags((byte) 0);
|
||||||
|
|
||||||
|
fsTextDisplay.setShadow(nametag.textShadow());
|
||||||
|
|
||||||
|
switch (nametag.textAlignment()) {
|
||||||
|
case LEFT -> fsTextDisplay.setAlignLeft(true);
|
||||||
|
case RIGHT -> fsTextDisplay.setAlignRight(true);
|
||||||
|
case CENTER -> {
|
||||||
|
fsTextDisplay.setAlignLeft(false);
|
||||||
|
fsTextDisplay.setAlignRight(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
for (String line : nametag.textLines()) {
|
||||||
|
text.append(line).append('\n');
|
||||||
|
}
|
||||||
|
text.deleteCharAt(text.length() - 1);
|
||||||
|
|
||||||
|
fsTextDisplay.setText(ModernChatColorHandler.translate(text.toString(), player));
|
||||||
|
|
||||||
|
FS_RealPlayer fsViewer = new FS_RealPlayer(viewer);
|
||||||
|
FancySitula.ENTITY_FACTORY.setEntityDataFor(fsViewer, fsTextDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void letDisplayRidePlayer(Player viewer) {
|
||||||
|
FS_RealPlayer fsViewer = new FS_RealPlayer(viewer);
|
||||||
|
|
||||||
|
FancySitula.PACKET_FACTORY.createSetPassengersPacket(
|
||||||
|
viewer.getEntityId(),
|
||||||
|
List.of(fsTextDisplay.getId())
|
||||||
|
).send(fsViewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisibleTo(Player viewer) {
|
||||||
|
return viewers.contains(viewer.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanViewers() {
|
||||||
|
viewers.removeIf(uuid -> {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
return player == null || !player.isOnline() || !player.getWorld().getName().equals(this.player.getWorld().getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Nametag getNametag() {
|
||||||
|
return nametag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<UUID> getViewers() {
|
||||||
|
return viewers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInDistance(Location loc1, Location loc2, double distance) {
|
||||||
|
return loc1.distanceSquared(loc2) <= distance * distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package de.oliver.fancyvisuals.nametags.visibility;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import de.oliver.fancyvisuals.utils.distributedWorkload.DistributedWorkload;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class PlayerNametagScheduler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ScheduledExecutorService instance responsible for scheduling periodic execution of
|
||||||
|
* the DistributedWorkload<PlayerNametag>. It manages the timing and frequency
|
||||||
|
* of workload distribution, ensuring that tasks are run at fixed intervals.
|
||||||
|
*/
|
||||||
|
private final ScheduledExecutorService schedulerExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DistributedWorkload instance responsible for managing and executing tasks related
|
||||||
|
* to PlayerNametag objects. It divides the tasks across multiple buckets and performs
|
||||||
|
* specified actions on each element. Actions include updating visibility and checking
|
||||||
|
* whether a PlayerNametag needs to be updated.
|
||||||
|
*/
|
||||||
|
private final DistributedWorkload<PlayerNametag> workload;
|
||||||
|
|
||||||
|
public PlayerNametagScheduler(ExecutorService workerExecutor, int bucketSize) {
|
||||||
|
this.schedulerExecutor = Executors.newSingleThreadScheduledExecutor(
|
||||||
|
new ThreadFactoryBuilder()
|
||||||
|
.setNameFormat("PlayerNametagScheduler")
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.workload = new DistributedWorkload<>(
|
||||||
|
"PlayerNametagWorkload",
|
||||||
|
PlayerNametag::updateVisibilityForAll,
|
||||||
|
(nt) -> !nt.getPlayer().isOnline(),
|
||||||
|
bucketSize,
|
||||||
|
workerExecutor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the PlayerNametagScheduler and starts the periodic execution
|
||||||
|
* of the DistributedWorkload<PlayerNametag>. The workload is scheduled to
|
||||||
|
* run at a fixed rate with an initial delay of 0 seconds and a period of
|
||||||
|
* 25 seconds between subsequent executions.
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
schedulerExecutor.scheduleWithFixedDelay(workload, 1000, 250, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(PlayerNametag nametag) {
|
||||||
|
workload.addValue(() -> nametag);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package de.oliver.fancyvisuals.playerConfig;
|
||||||
|
|
||||||
|
import de.oliver.fancylib.jdb.JDB;
|
||||||
|
import de.oliver.fancyvisuals.FancyVisuals;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@code JsonPlayerConfigStore} class is responsible for handling player configuration storage and retrieval using JSON.
|
||||||
|
* It interacts with an underlying JSON database to manage {@code PlayerConfig} instances for individual players.
|
||||||
|
*/
|
||||||
|
public class JsonPlayerConfigStore {
|
||||||
|
|
||||||
|
private static final String BASE_PATH = "plugins/FancyVisuals/data/player-configs/";
|
||||||
|
private static final PlayerConfig DEFAULT_PLAYER_CONFIG = new PlayerConfig(true);
|
||||||
|
private final JDB jdb;
|
||||||
|
|
||||||
|
public JsonPlayerConfigStore() {
|
||||||
|
jdb = new JDB(BASE_PATH);
|
||||||
|
|
||||||
|
// Generate default player config if not present
|
||||||
|
getDefaultPlayerConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the PlayerConfig for a specific player identified by their UUID.
|
||||||
|
* If the PlayerConfig is not found, the default PlayerConfig is returned.
|
||||||
|
*
|
||||||
|
* @param uuid the unique identifier of the player whose configuration is being retrieved.
|
||||||
|
* @return the PlayerConfig associated with the given UUID, or the default PlayerConfig if none is found.
|
||||||
|
*/
|
||||||
|
public @NotNull PlayerConfig getPlayerConfig(@NotNull UUID uuid) {
|
||||||
|
PlayerConfig playerConfig = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
playerConfig = jdb.get(uuid.toString(), PlayerConfig.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to get player config for uuid " + uuid);
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerConfig != null ? playerConfig : getDefaultPlayerConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the configuration for a specific player identified by the UUID.
|
||||||
|
*
|
||||||
|
* @param uuid the unique identifier of the player for whom the configuration is to be set
|
||||||
|
* @param playerConfig the PlayerConfig object containing the new configuration settings for the player
|
||||||
|
*/
|
||||||
|
public void setPlayerConfig(@NotNull UUID uuid, @NotNull PlayerConfig playerConfig) {
|
||||||
|
try {
|
||||||
|
jdb.set(uuid.toString(), playerConfig);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to set player config for uuid " + uuid);
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the player configuration associated with the specified UUID.
|
||||||
|
*
|
||||||
|
* @param uuid the unique identifier of the player whose configuration is to be deleted
|
||||||
|
*/
|
||||||
|
public void deletePlayerConfig(@NotNull UUID uuid) {
|
||||||
|
jdb.delete(uuid.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the default PlayerConfig.
|
||||||
|
* If the default PlayerConfig is not found in the database, it sets and returns the predefined default configuration.
|
||||||
|
*
|
||||||
|
* @return the default PlayerConfig. If not present, the predefined default PlayerConfig is set and returned.
|
||||||
|
*/
|
||||||
|
public PlayerConfig getDefaultPlayerConfig() {
|
||||||
|
PlayerConfig playerConfig = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
playerConfig = jdb.get("default", PlayerConfig.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to get default player config");
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerConfig == null) {
|
||||||
|
playerConfig = DEFAULT_PLAYER_CONFIG;
|
||||||
|
|
||||||
|
try {
|
||||||
|
jdb.set("default", DEFAULT_PLAYER_CONFIG);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FancyVisuals.getFancyLogger().error("Failed to set default player config");
|
||||||
|
FancyVisuals.getFancyLogger().error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package de.oliver.fancyvisuals.playerConfig;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the configuration settings for a player.
|
||||||
|
*
|
||||||
|
* @param showOwnNametag indicates whether the player should see their own nametag.
|
||||||
|
*/
|
||||||
|
public record PlayerConfig(
|
||||||
|
@SerializedName("show_own_nametag")
|
||||||
|
boolean showOwnNametag
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package de.oliver.fancyvisuals.utils;
|
||||||
|
|
||||||
|
import net.milkbowl.vault.permission.Permission;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
|
||||||
|
|
||||||
|
public class VaultHelper {
|
||||||
|
|
||||||
|
private static boolean vaultLoaded = false;
|
||||||
|
private static Permission permission;
|
||||||
|
|
||||||
|
public static void loadVault() {
|
||||||
|
vaultLoaded = Bukkit.getPluginManager().getPlugin("Vault") != null;
|
||||||
|
if (!vaultLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredServiceProvider<Permission> rsp = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
|
||||||
|
permission = rsp == null ? null : rsp.getProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isVaultLoaded() {
|
||||||
|
return vaultLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Permission getPermission() {
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package de.oliver.fancyvisuals.utils.distributedWorkload;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Bucket provides storage for entries, which are suppliers that yield elements of the
|
||||||
|
* specified type. It allows adding entries and performing actions on them, with optional
|
||||||
|
* asynchronous execution.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the elements in the bucket
|
||||||
|
*/
|
||||||
|
public class Bucket<T> {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final LinkedList<Supplier<T>> entries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an empty Bucket.
|
||||||
|
*/
|
||||||
|
public Bucket(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.entries = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new entry to the bucket.
|
||||||
|
*
|
||||||
|
* @param entry the supplier providing the entry to be added to the bucket
|
||||||
|
*/
|
||||||
|
public void addEntry(Supplier<T> entry) {
|
||||||
|
entries.add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes an action for each entry in the bucket. If the action is set to be
|
||||||
|
* executed asynchronously, it will run in separate threads; otherwise, it will
|
||||||
|
* execute in the current thread.
|
||||||
|
*
|
||||||
|
* @param action the action to be performed on each entry
|
||||||
|
* @param escape a condition to determine which entries should be removed after the action is performed
|
||||||
|
* @param executor the executor service to be used for asynchronous execution
|
||||||
|
*/
|
||||||
|
public void executeAction(Consumer<T> action, Predicate<T> escape, ExecutorService executor) {
|
||||||
|
LinkedList<Supplier<T>> suppliers = new LinkedList<>(entries);
|
||||||
|
|
||||||
|
for (Supplier<T> supplier : suppliers) {
|
||||||
|
executor.submit(() -> action.accept(supplier.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.removeIf(s -> escape.test(s.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package de.oliver.fancyvisuals.utils.distributedWorkload;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DistributedWorkload is a class that manages and executes a workload distributed across multiple buckets.
|
||||||
|
* Each bucket contains a subset of the workload and executes a specified action on its elements.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the elements in the workload
|
||||||
|
*/
|
||||||
|
public class DistributedWorkload<T> implements Runnable {
|
||||||
|
|
||||||
|
private final String workloadName;
|
||||||
|
private final Consumer<T> action;
|
||||||
|
private final Predicate<T> escapeCondition;
|
||||||
|
private final int bucketSize;
|
||||||
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
|
private final List<Bucket<T>> buckets;
|
||||||
|
private int currentBucket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DistributedWorkload instance.
|
||||||
|
*
|
||||||
|
* @param workloadName the name of the workload
|
||||||
|
* @param action the action to be performed on each element of the workload
|
||||||
|
* @param escapeCondition a condition to determine which elements should be removed after the action is performed
|
||||||
|
* @param bucketSize the number of buckets into which the workload will be split
|
||||||
|
* @param executorService the executor service to be used for asynchronous execution
|
||||||
|
*/
|
||||||
|
public DistributedWorkload(String workloadName, Consumer<T> action, Predicate<T> escapeCondition, int bucketSize, ExecutorService executorService) {
|
||||||
|
this.workloadName = workloadName;
|
||||||
|
this.action = action;
|
||||||
|
this.escapeCondition = escapeCondition;
|
||||||
|
this.bucketSize = bucketSize;
|
||||||
|
this.executorService = executorService;
|
||||||
|
|
||||||
|
this.currentBucket = 0;
|
||||||
|
this.buckets = new ArrayList<>(bucketSize);
|
||||||
|
for (int i = 0; i < bucketSize; i++) {
|
||||||
|
this.buckets.add(new Bucket<>("DWL-" + workloadName + "-" + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the next bucket of workload by invoking the runNextBucket method.
|
||||||
|
* This method is called when this instance is run as a Runnable.
|
||||||
|
* Each bucket contains a portion of the workload and executes the specified action
|
||||||
|
* on each of its elements, either synchronously or asynchronously,
|
||||||
|
* depending on the configuration of the DistributedWorkload.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
runNextBucket();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new value to the smallest bucket within the distributed workload.
|
||||||
|
* The value is supplied by the specified Supplier.
|
||||||
|
*
|
||||||
|
* @param valueSupplier the supplier providing the value to be added to the bucket
|
||||||
|
*/
|
||||||
|
public void addValue(Supplier<T> valueSupplier) {
|
||||||
|
Bucket<T> smallestBucket = buckets.getFirst();
|
||||||
|
|
||||||
|
for (int i = 1; i < bucketSize; i++) {
|
||||||
|
if (smallestBucket.size() == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buckets.get(i).size() < smallestBucket.size()) {
|
||||||
|
smallestBucket = buckets.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smallestBucket.addEntry(valueSupplier);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advances to the next bucket in the list and executes its action.
|
||||||
|
* If the current bucket is the last one in the list, it wraps around to the first bucket.
|
||||||
|
* The action is executed on each element of the current bucket according to the configured
|
||||||
|
* conditions and can be run asynchronously if specified.
|
||||||
|
*/
|
||||||
|
private void runNextBucket() {
|
||||||
|
currentBucket++;
|
||||||
|
if (currentBucket >= buckets.size()) {
|
||||||
|
currentBucket = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bucket<T> bucket = buckets.get(currentBucket);
|
||||||
|
bucket.executeAction(action, escapeCondition, executorService);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ include(":plugins:fancyholograms:implementation_1_20_2")
|
|||||||
include(":plugins:fancyholograms:implementation_1_20_1")
|
include(":plugins:fancyholograms:implementation_1_20_1")
|
||||||
include(":plugins:fancyholograms:implementation_1_19_4")
|
include(":plugins:fancyholograms:implementation_1_19_4")
|
||||||
|
|
||||||
|
include(":plugins:fancyvisuals")
|
||||||
|
include(":plugins:fancyvisuals:api")
|
||||||
|
|
||||||
include(":libraries:common")
|
include(":libraries:common")
|
||||||
include(":libraries:jdb")
|
include(":libraries:jdb")
|
||||||
include(":libraries:plugin-tests")
|
include(":libraries:plugin-tests")
|
||||||
|
|||||||
Reference in New Issue
Block a user