mirror of
https://github.com/FancyInnovations/FancyPlugins.git
synced 2025-12-05 23:33:36 +00:00
Add FancyVisuals plugin
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
fancyhologramsVersion=2.4.2
|
||||
fancyvisualsVersion=0.0.1
|
||||
fancylibVersion=36
|
||||
fancysitulaVersion=0.0.13
|
||||
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_19_4")
|
||||
|
||||
include(":plugins:fancyvisuals")
|
||||
include(":plugins:fancyvisuals:api")
|
||||
|
||||
include(":libraries:common")
|
||||
include(":libraries:jdb")
|
||||
include(":libraries:plugin-tests")
|
||||
|
||||
Reference in New Issue
Block a user