Merge branch 'main' into fix/folia-visibility-issues

This commit is contained in:
Oliver
2025-11-18 11:33:10 +01:00
committed by GitHub
161 changed files with 4456 additions and 485 deletions

View File

@@ -1 +1 @@
0.0.24
0.0.32

View File

@@ -8,19 +8,10 @@ plugins {
id("xyz.jpenilla.run-paper")
id("com.gradleup.shadow")
id("de.eldoria.plugin-yml.paper")
id("io.papermc.hangar-publish-plugin")
id("com.modrinth.minotaur")
}
runPaper.folia.registerTask()
val supportedVersions =
listOf(
"1.21.6",
"1.21.7",
"1.21.8",
)
allprojects {
group = "de.oliver"
version = getFDVersion()
@@ -42,7 +33,7 @@ allprojects {
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.9-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
implementation(project(":plugins:fancydialogs:fd-api"))
@@ -59,7 +50,7 @@ dependencies {
implementation("de.oliver.FancyAnalytics:logger:0.0.8")
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
implementation("io.github.revxrsal:lamp.common:4.0.0-rc.12")
implementation("io.github.revxrsal:lamp.bukkit:4.0.0-rc.12")
@@ -94,10 +85,10 @@ paper {
tasks {
runServer {
minecraftVersion("1.21.9")
minecraftVersion("1.21.10")
downloadPlugins {
modrinth("fancynpcs", "2.6.0.283")
modrinth("fancynpcs", "2.8.0")
// hangar("ViaVersion", "5.3.2")
// hangar("ViaBackwards", "5.3.2")
// modrinth("multiverse-core", "4.3.11")
@@ -146,14 +137,6 @@ tasks {
}
}
tasks.publishAllPublicationsToHangar {
dependsOn("shadowJar")
}
tasks.modrinth {
dependsOn("shadowJar")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
@@ -168,35 +151,4 @@ val gitCommitMessage: Provider<String> = providers.exec {
fun getFDVersion(): String {
return file("VERSION").readText()
}
hangarPublish {
publications.register("plugin") {
version = project.version as String
id = "FancyDialogs"
channel = "Alpha"
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
platforms {
paper {
jar = tasks.shadowJar.flatMap { it.archiveFile }
platformVersions = supportedVersions
}
}
changelog = gitCommitMessage.get()
}
}
modrinth {
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
projectId.set("FancyDialogs")
versionNumber.set(getFDVersion())
versionType.set("alpha")
uploadFile.set(file("build/libs/${project.name}-${getFDVersion()}.jar"))
gameVersions.addAll(supportedVersions)
loaders.add("paper")
loaders.add("folia")
changelog.set(gitCommitMessage.get())
}

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":libraries:common"))
compileOnly("de.oliver.FancyAnalytics:logger:0.0.8")
implementation("org.lushplugins:ChatColorHandler:6.0.2")
implementation("org.lushplugins:ChatColorHandler:6.0.0")
implementation("org.jetbrains:annotations:24.0.0")
}

View File

@@ -4,6 +4,7 @@ import com.fancyinnovations.fancydialogs.api.data.DialogData;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -12,12 +13,12 @@ public abstract class Dialog {
protected String id;
protected DialogData data;
protected Set<UUID> viewers;
protected Map<UUID, Long> viewers; // uuid, time opened
public Dialog(String id, DialogData data) {
this.id = id;
this.data = data;
this.viewers = ConcurrentHashMap.newKeySet();
this.viewers = new ConcurrentHashMap<>();
}
public Dialog() {
@@ -49,7 +50,7 @@ public abstract class Dialog {
* @return a set of UUIDs of players who have this dialog opened
*/
public Set<UUID> getViewers() {
return Set.copyOf(viewers);
return Set.copyOf(viewers.keySet());
}
/**
@@ -58,13 +59,7 @@ public abstract class Dialog {
* @param uuid of the player to check
* @return true if the dialog is opened for the player, false otherwise
*/
public boolean isOpenedFor(UUID uuid) {
if (uuid == null) {
return false;
}
return viewers.contains(uuid);
}
public abstract boolean isOpenedFor(UUID uuid);
/***
* Checks if the dialog is opened for a specific player.
@@ -85,7 +80,8 @@ public abstract class Dialog {
if (player == null) {
return;
}
viewers.add(player.getUniqueId());
viewers.put(player.getUniqueId(), System.currentTimeMillis());
}
@ApiStatus.Internal
@@ -93,6 +89,7 @@ public abstract class Dialog {
if (player == null) {
return;
}
viewers.remove(player.getUniqueId());
}
}

View File

@@ -1,9 +1,12 @@
package com.fancyinnovations.fancydialogs.api;
package com.fancyinnovations.fancydialogs.api.dialogs;
import com.fancyinnovations.fancydialogs.api.Dialog;
import com.fancyinnovations.fancydialogs.api.FancyDialogs;
import com.fancyinnovations.fancydialogs.api.data.DialogBodyData;
import com.fancyinnovations.fancydialogs.api.data.DialogButton;
import com.fancyinnovations.fancydialogs.api.data.DialogData;
import com.fancyinnovations.fancydialogs.api.data.inputs.DialogInputs;
import com.fancyinnovations.fancydialogs.api.data.inputs.DialogTextField;
import org.bukkit.entity.Player;
import java.util.List;
@@ -19,6 +22,7 @@ public class ConfirmationDialog {
private String title = "Confirmation";
private String confirmText = "Yes";
private String cancelText = "No";
private String expectedUserInput = "";
private Dialog dialog;
private String confirmButtonId;
@@ -28,7 +32,7 @@ public class ConfirmationDialog {
private Runnable onCancel = () -> {
};
public ConfirmationDialog(String title, String question, String confirmText, String cancelText, Runnable onConfirm, Runnable onCancel) {
public ConfirmationDialog(String title, String question, String confirmText, String cancelText, String expectedUserInput, Runnable onConfirm, Runnable onCancel) {
this.title = title;
this.question = question;
this.confirmText = confirmText;
@@ -56,6 +60,11 @@ public class ConfirmationDialog {
return this;
}
public ConfirmationDialog withExpectedUserInput(String expectedUserInput) {
this.expectedUserInput = expectedUserInput;
return this;
}
public ConfirmationDialog withOnConfirm(Runnable onConfirm) {
this.onConfirm = onConfirm;
return this;
@@ -103,18 +112,31 @@ public class ConfirmationDialog {
);
this.cancelButtonId = cancelBtn.id();
List<DialogTextField> textFields = null;
if (expectedUserInput != null && !expectedUserInput.isEmpty()) {
textFields = List.of(
new DialogTextField("confirmation_user_input", "Type '" + expectedUserInput + "' to confirm", 0, "", expectedUserInput.length(), 1)
);
}
DialogInputs inputs = new DialogInputs(textFields, null, null);
DialogData dialogData = new DialogData(
"confirmation_dialog_" + UUID.randomUUID(),
title,
false,
List.of(new DialogBodyData(question)),
DialogInputs.EMPTY, // TODO add support for confirmation phrases
inputs,
List.of(confirmBtn, cancelBtn)
);
this.dialog = FancyDialogs.get().createDialog(dialogData);
}
public String getExpectedUserInput() {
return expectedUserInput;
}
public String getConfirmButtonId() {
return confirmButtonId;
}

View File

@@ -1,5 +1,6 @@
package com.fancyinnovations.fancydialogs.api;
package com.fancyinnovations.fancydialogs.api.dialogs;
import com.fancyinnovations.fancydialogs.api.FancyDialogs;
import com.fancyinnovations.fancydialogs.api.data.DialogBodyData;
import com.fancyinnovations.fancydialogs.api.data.DialogData;
import com.fancyinnovations.fancydialogs.api.data.inputs.DialogInputs;

View File

@@ -6,6 +6,8 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class DialogButtonClickedEvent extends Event {
private static final HandlerList handlerList = new HandlerList();
@@ -13,12 +15,14 @@ public class DialogButtonClickedEvent extends Event {
private final Player player;
private final String dialogId;
private final String buttonId;
private final Map<String, String> payload;
public DialogButtonClickedEvent(@NotNull Player player, @NotNull String dialogId, @NotNull String buttonId) {
public DialogButtonClickedEvent(@NotNull Player player, @NotNull String dialogId, @NotNull String buttonId, @NotNull Map<String, String> payload) {
super(!Bukkit.isPrimaryThread());
this.player = player;
this.dialogId = dialogId;
this.buttonId = buttonId;
this.payload = payload;
}
public static HandlerList getHandlerList() {
@@ -37,6 +41,10 @@ public class DialogButtonClickedEvent extends Event {
return buttonId;
}
public Map<String, String> getPayload() {
return payload;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlerList;

View File

@@ -8,7 +8,9 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10",
"1.21.11"
],
"channel": "RELEASE",
"loaders": [

View File

@@ -8,7 +8,8 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10"
],
"channel": "BETA",
"loaders": [

View File

@@ -9,7 +9,6 @@ import com.fancyinnovations.fancydialogs.api.data.DialogData;
import com.fancyinnovations.fancydialogs.commands.DialogCMD;
import com.fancyinnovations.fancydialogs.commands.FancyDialogsCMD;
import com.fancyinnovations.fancydialogs.commands.QuickActionsCMD;
import com.fancyinnovations.fancydialogs.commands.TutorialCMD;
import com.fancyinnovations.fancydialogs.commands.types.DialogCommandType;
import com.fancyinnovations.fancydialogs.config.FDFeatureFlags;
import com.fancyinnovations.fancydialogs.config.FancyDialogsConfig;
@@ -243,7 +242,6 @@ public class FancyDialogsPlugin extends JavaPlugin implements FancyDialogs {
lamp.register(FancyDialogsCMD.INSTANCE);
lamp.register(DialogCMD.INSTANCE);
lamp.register(TutorialCMD.INSTANCE);
if (!FDFeatureFlags.DISABLE_QUICK_ACTIONS_DIALOG.isEnabled()) {
lamp.register(QuickActionsCMD.INSTANCE);
}

View File

@@ -1,9 +1,9 @@
package com.fancyinnovations.fancydialogs.commands;
import com.fancyinnovations.fancydialogs.FancyDialogsPlugin;
import com.fancyinnovations.fancydialogs.api.ConfirmationDialog;
import com.fancyinnovations.fancydialogs.api.Dialog;
import com.fancyinnovations.fancydialogs.api.data.DialogData;
import com.fancyinnovations.fancydialogs.api.dialogs.ConfirmationDialog;
import com.fancyinnovations.fancydialogs.config.FancyDialogsConfig;
import com.fancyinnovations.fancydialogs.dialog.DialogImpl;
import de.oliver.fancyanalytics.logger.LogLevel;

View File

@@ -1,29 +0,0 @@
package com.fancyinnovations.fancydialogs.commands;
import com.fancyinnovations.fancydialogs.FancyDialogsPlugin;
import de.oliver.fancylib.translations.Translator;
import revxrsal.commands.annotation.Command;
import revxrsal.commands.annotation.Description;
import revxrsal.commands.bukkit.actor.BukkitCommandActor;
import revxrsal.commands.bukkit.annotation.CommandPermission;
public final class TutorialCMD {
public static final TutorialCMD INSTANCE = new TutorialCMD();
private final FancyDialogsPlugin plugin = FancyDialogsPlugin.get();
private final Translator translator = FancyDialogsPlugin.get().getTranslator();
private TutorialCMD() {
}
@Command("tutorial open <tutorial>")
@Description("Opens a specific tutorial dialog")
@CommandPermission("fancydialogs.commands.tutorial")
public void onTutorialOpen(
final BukkitCommandActor actor,
final String tutorial
) {
actor.requirePlayer().sendMessage("Opening tutorial: " + tutorial);
}
}

View File

@@ -12,6 +12,7 @@ public class FancyDialogsConfig {
private String logLevel;
private String welcomeDialogID;
private String quickActionsDialogID;
private int closeTimeout;
public void load() {
FancyDialogsPlugin.get().reloadConfig();
@@ -29,6 +30,9 @@ public class FancyDialogsConfig {
quickActionsDialogID = (String) ConfigHelper.getOrDefault(config, "quick_actions_dialog_id", "quick_actions");
config.setInlineComments("quick_actions_dialog_id", List.of("The ID of the dialog which will be shown to the player when they click on the quick actions key ('G' by default)."));
closeTimeout = (int) ConfigHelper.getOrDefault(config, "close_timeout", 1000 * 60 * 2);
config.setInlineComments("close_timeout", List.of("The time in milliseconds after which a dialog will be considered closed if the player does not respond. 0 means no timeout."));
FancyDialogsPlugin.get().saveConfig();
}
@@ -47,4 +51,8 @@ public class FancyDialogsConfig {
public String getQuickActionsDialogID() {
return quickActionsDialogID;
}
public int getCloseTimeout() {
return closeTimeout;
}
}

View File

@@ -27,6 +27,7 @@ import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class DialogImpl extends Dialog {
@@ -177,7 +178,7 @@ public class DialogImpl extends Dialog {
.createShowDialogPacket(buildForPlayer(player))
.send(new FS_RealPlayer(player));
viewers.add(player.getUniqueId());
addViewer(player);
FancyDialogsPlugin.get().getFancyLogger().debug("Opened dialog " + id + " for player " + player.getName());
}
@@ -188,9 +189,29 @@ public class DialogImpl extends Dialog {
.createClearDialogPacket()
.send(new FS_RealPlayer(player));
viewers.remove(player.getUniqueId());
removeViewer(player);
FancyDialogsPlugin.get().getFancyLogger().debug("Closed dialog " + id + " for player " + player.getName());
}
@Override
public boolean isOpenedFor(UUID uuid) {
if (uuid == null) {
return false;
}
if (!viewers.containsKey(uuid)) {
return false;
}
long openedAt = viewers.get(uuid);
long now = System.currentTimeMillis();
if (now - openedAt > FancyDialogsPlugin.get().getFancyDialogsConfig().getCloseTimeout()) {
viewers.remove(uuid);
return false;
}
return true;
}
}

View File

@@ -46,7 +46,7 @@ public class CustomClickActionPacketListener {
String dialogId = packet.getPayload().get("dialog_id");
String buttonId = packet.getPayload().get("button_id");
new DialogButtonClickedEvent(event.player(), dialogId, buttonId).callEvent();
new DialogButtonClickedEvent(event.player(), dialogId, buttonId, packet.getPayload()).callEvent();
if (dialogId.startsWith("confirmation_dialog_")) {
return; // Ignore confirmation dialog actions, handled separately

View File

@@ -1,6 +1,7 @@
package com.fancyinnovations.fancydialogs.listener;
import com.fancyinnovations.fancydialogs.api.ConfirmationDialog;
import com.fancyinnovations.fancydialogs.FancyDialogsPlugin;
import com.fancyinnovations.fancydialogs.api.dialogs.ConfirmationDialog;
import com.fancyinnovations.fancydialogs.api.events.DialogButtonClickedEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -16,6 +17,21 @@ public class DialogButtonClickedListener implements Listener {
}
if (event.getButtonId().equals(dialog.getConfirmButtonId())) {
if (dialog.getExpectedUserInput() != null && !dialog.getExpectedUserInput().isEmpty()) {
if (!event.getPayload().containsKey("confirmation_user_input")) {
FancyDialogsPlugin.get().getFancyLogger().warn("Confirmation dialog expected user input but none was provided.");
return;
}
String userInput = event.getPayload().get("confirmation_user_input");
if (!userInput.equals(dialog.getExpectedUserInput())) {
FancyDialogsPlugin.get().getTranslator()
.translate("confirmation_dialog.input_mismatch")
.send(event.getPlayer());
return;
}
}
dialog.getOnConfirm().run();
ConfirmationDialog.CACHE.remove(event.getDialogId());
} else if (event.getButtonId().equals(dialog.getCancelButtonId())) {

View File

@@ -2,6 +2,8 @@ language_name: default
messages:
dialog:
not_found: "<dark_gray> <gray>Dialog {warningColor}{id}<gray> is not registered."
confirmation_dialog:
input_mismatch: "<dark_gray> <gray>Your input does not match the expected phrase."
commands:
dialog:
open:

View File

@@ -1,3 +1 @@
- Improved performance by running more tasks asynchronously
- Improved logging
- Added HologramManager#isLoaded method
- Added support for 1.21.11

View File

@@ -1 +1 @@
2.7.0.154
2.8.0.158

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":libraries:common"))
compileOnly("de.oliver.FancyAnalytics:logger:0.0.8")
implementation("org.lushplugins:ChatColorHandler:6.0.2")
implementation("org.lushplugins:ChatColorHandler:6.0.0")
}
tasks {

View File

@@ -8,33 +8,10 @@ plugins {
id("xyz.jpenilla.run-paper")
id("com.gradleup.shadow")
id("de.eldoria.plugin-yml.paper")
id("io.papermc.hangar-publish-plugin")
id("com.modrinth.minotaur")
}
runPaper.folia.registerTask()
val supportedVersions =
listOf(
"1.19.4",
"1.20",
"1.20.1",
"1.20.2",
"1.20.3",
"1.20.4",
"1.20.5",
"1.20.6",
"1.21",
"1.21.1",
"1.21.2",
"1.21.3",
"1.21.4",
"1.21.5",
"1.21.6",
"1.21.7",
"1.21.8",
)
allprojects {
group = "de.oliver"
version = getFHVersion()
@@ -56,7 +33,7 @@ allprojects {
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.9-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
implementation(project(":plugins:fancyholograms-v2:api"))
implementation(project(":plugins:fancyholograms-v2:implementation_1_20_4", configuration = "reobf"))
@@ -77,7 +54,7 @@ dependencies {
implementation("de.oliver.FancyAnalytics:logger:0.0.8")
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT")
}
@@ -114,7 +91,7 @@ paper {
tasks {
runServer {
minecraftVersion("1.21.9")
minecraftVersion("1.21.10")
downloadPlugins {
// modrinth("fancynpcs", "2.5.2")
@@ -167,14 +144,6 @@ tasks {
}
}
tasks.publishAllPublicationsToHangar {
dependsOn("shadowJar")
}
tasks.modrinth {
dependsOn("shadowJar")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
@@ -190,34 +159,3 @@ val gitCommitMessage: Provider<String> = providers.exec {
fun getFHVersion(): String {
return file("VERSION").readText()
}
hangarPublish {
publications.register("plugin") {
version = project.version as String
id = "FancyHolograms"
channel = "Alpha"
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
platforms {
paper {
jar = tasks.shadowJar.flatMap { it.archiveFile }
platformVersions = supportedVersions
}
}
changelog = gitCommitMessage.get()
}
}
modrinth {
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
projectId.set("fancyholograms")
versionNumber.set(getFHVersion())
versionType.set("alpha")
uploadFile.set(file("build/libs/${project.name}-${getFHVersion()}.jar"))
gameVersions.addAll(supportedVersions)
loaders.add("paper")
loaders.add("folia")
changelog.set(gitCommitMessage.get())
}

View File

@@ -22,7 +22,9 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10",
"1.21.11"
],
"channel": "RELEASE",
"loaders": [

View File

@@ -22,7 +22,8 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10"
],
"channel": "BETA",
"loaders": [

View File

@@ -292,7 +292,7 @@ public final class FancyHolograms extends JavaPlugin implements FancyHologramsPl
private void registerListeners() {
getServer().getPluginManager().registerEvents(new PlayerListener(this), this);
getServer().getPluginManager().registerEvents(new WorldListener(), this);
if (Bukkit.getMinecraftVersion().equals("1.21.4") || Bukkit.getMinecraftVersion().equals("1.21.5") || Bukkit.getMinecraftVersion().equals("1.21.6") || Bukkit.getMinecraftVersion().equals("1.21.7") || Bukkit.getMinecraftVersion().equals("1.21.8")) {
if (Set.of("1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8").contains(Bukkit.getMinecraftVersion())) {
getServer().getPluginManager().registerEvents(new PlayerLoadedListener(), this);
}

View File

@@ -1,5 +1,6 @@
**ATTENTION**: v3 is still in development and contains breaking changes and potential bugs.
Do not use this version in production at all, or you may lose data!!
**ATTENTION**: v3 is still in development and contains breaking changes and potential bugs.
Do not use this version in production at all, or you may lose data!
Once migrated to v3, you cannot go back to v2 without losing all your holograms and configurations!
Commit hash: %COMMIT_HASH%

View File

@@ -1 +1 @@
3.0.0-SNAPSHOT.6
3.0.0-SNAPSHOT.11

View File

@@ -8,27 +8,10 @@ plugins {
id("xyz.jpenilla.run-paper")
id("com.gradleup.shadow")
id("de.eldoria.plugin-yml.paper")
id("io.papermc.hangar-publish-plugin")
id("com.modrinth.minotaur")
}
runPaper.folia.registerTask()
val supportedVersions =
listOf(
"1.20.5",
"1.20.6",
"1.21",
"1.21.1",
"1.21.2",
"1.21.3",
"1.21.4",
"1.21.5",
"1.21.6",
"1.21.7",
"1.21.8",
)
allprojects {
group = "de.oliver"
version = getFHVersion()
@@ -50,7 +33,7 @@ allprojects {
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.9-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
implementation(project(":plugins:fancyholograms:fh-api"))
@@ -70,7 +53,7 @@ dependencies {
implementation("io.github.revxrsal:lamp.common:4.0.0-rc.12")
implementation("io.github.revxrsal:lamp.bukkit:4.0.0-rc.12")
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
compileOnly("com.viaversion:viaversion-api:5.2.1")
compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT")
}
@@ -113,7 +96,7 @@ paper {
tasks {
runServer {
minecraftVersion("1.21.9")
minecraftVersion("1.21.10")
downloadPlugins {
modrinth("fancynpcs", "2.7.0")
@@ -162,14 +145,6 @@ tasks {
}
}
tasks.publishAllPublicationsToHangar {
dependsOn("shadowJar")
}
tasks.modrinth {
dependsOn("shadowJar")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
@@ -185,34 +160,3 @@ fun getLastCommitMessage(): String {
fun getFHVersion(): String {
return file("VERSION").readText()
}
hangarPublish {
publications.register("plugin") {
version = getFHVersion()
id = "FancyHolograms"
channel = "Alpha"
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
platforms {
paper {
jar = tasks.shadowJar.flatMap { it.archiveFile }
platformVersions = supportedVersions
}
}
changelog = getLastCommitMessage()
}
}
modrinth {
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
projectId.set("fancyholograms")
versionNumber.set(getFHVersion())
versionType.set("alpha")
uploadFile.set(file("build/libs/FancyHolograms-${getFHVersion()}.jar"))
gameVersions.addAll(supportedVersions)
loaders.add("paper")
loaders.add("folia")
changelog.set(getLastCommitMessage())
}

View File

@@ -13,7 +13,7 @@ dependencies {
compileOnly(project(":libraries:jdb"))
compileOnly("de.oliver.FancyAnalytics:logger:0.0.8")
implementation("org.lushplugins:ChatColorHandler:6.0.2")
implementation("org.lushplugins:ChatColorHandler:6.0.0")
}
tasks {

View File

@@ -16,7 +16,9 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10",
"1.21.11"
],
"channel": "RELEASE",
"loaders": [

View File

@@ -16,7 +16,8 @@
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9"
"1.21.9",
"1.21.10"
],
"channel": "ALPHA",
"loaders": [

View File

@@ -202,10 +202,6 @@ public final class HologramCMD extends Command {
return Collections.emptyList();
}
if (args[2].equalsIgnoreCase("traits")) {
return new TraitsCMD().tabcompletion(sender, hologram, args);
}
// /holo edit [hologram] [option] {tab:contextual}
if (args.length == 4) {
final var suggestions = switch (args[2].toLowerCase(Locale.ROOT)) {
@@ -354,9 +350,6 @@ public final class HologramCMD extends Command {
}
return switch (action) {
// hologram data
case "traits" -> new TraitsCMD().run(player, hologram, args);
// display data
case "moveto" -> new MoveToCMD().run(player, hologram, args);
case "rotate" -> new RotateCMD().run(player, hologram, args);

View File

@@ -1,94 +0,0 @@
package com.fancyinnovations.fancyholograms.commands.hologram;
import com.fancyinnovations.fancyholograms.api.FancyHolograms;
import com.fancyinnovations.fancyholograms.api.hologram.Hologram;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry;
import com.fancyinnovations.fancyholograms.commands.Subcommand;
import de.oliver.fancylib.MessageHelper;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class TraitsCMD implements Subcommand {
@Override
public List<String> tabcompletion(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) {
if (args.length == 4) {
return List.of("add", "remove");
} else if (args.length == 5) {
return FancyHolograms.get().getTraitRegistry().getTraits()
.stream()
.filter(ti -> !ti.isDefault())
.filter(ti -> {
if (args[3].equalsIgnoreCase("add")) {
return !hologram.getData().getTraitTrait().isTraitAttached(ti.clazz());
} else if (args[3].equalsIgnoreCase("remove")) {
return hologram.getData().getTraitTrait().isTraitAttached(ti.clazz());
}
return true;
})
.map(HologramTraitRegistry.TraitInfo::name)
.toList();
}
return List.of();
}
@Override
public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) {
if (!(player.hasPermission("fancyholograms.hologram.edit.traits"))) {
MessageHelper.error(player, "You don't have the required permission to change traits of a hologram.");
return false;
}
// /hologram edit <name> traits <add|remove> <trait name>
if (args.length < 5) {
MessageHelper.error(player, "Usage: /hologram edit <name> traits <add|remove> <trait name>");
return false;
}
String action = args[3];
String traitName = args[4];
if (traitName == null || traitName.isEmpty()) {
MessageHelper.error(player, "You must specify a trait name.");
return false;
}
HologramTraitRegistry.TraitInfo traitInfo = FancyHolograms.get().getTraitRegistry().getTrait(traitName);
if (traitInfo == null) {
MessageHelper.error(player, "Trait '" + traitName + "' does not exist.");
return false;
}
switch (action.toLowerCase()) {
case "add": {
if (hologram.getData().getTraitTrait().isTraitAttached(traitInfo.clazz())) {
MessageHelper.error(player, "Trait '" + traitName + "' is already attached to hologram '" + hologram.getData().getName() + "'.");
return false;
}
hologram.getData().getTraitTrait().addTrait(traitInfo.clazz());
MessageHelper.success(player, "Trait '" + traitName + "' has been added to hologram '" + hologram.getData().getName() + "'.");
return true;
}
case "remove": {
if (!hologram.getData().getTraitTrait().isTraitAttached(traitInfo.clazz())) {
MessageHelper.error(player, "Trait '" + traitName + "' is not attached to hologram '" + hologram.getData().getName() + "'.");
return false;
}
hologram.getData().getTraitTrait().removeTrait(traitInfo.clazz());
MessageHelper.success(player, "Trait '" + traitName + "' has been removed from hologram '" + hologram.getData().getName() + "'.");
return true;
}
default: {
MessageHelper.error(player, "Invalid action. Use 'add' or 'remove'.");
return false;
}
}
}
}

View File

@@ -1,7 +1,9 @@
package com.fancyinnovations.fancyholograms.commands.lampCommands.hologram;
import com.fancyinnovations.fancyholograms.api.hologram.Hologram;
import com.fancyinnovations.fancyholograms.api.trait.HologramTrait;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitRegistry;
import com.fancyinnovations.fancyholograms.api.trait.HologramTraitTrait;
import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.AttachedTraitsSuggestion;
import com.fancyinnovations.fancyholograms.commands.lampCommands.suggestions.DetachedTraitsSuggestion;
import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin;
@@ -70,4 +72,30 @@ public final class TraitCMD {
.replace("name", trait.name())
.send(actor.sender());
}
@Command("hologram-new edit <hologram> trait list")
@Description("Lists all attached traits of a hologram")
@CommandPermission("fancyholograms.commands.hologram.trait.list")
public void list(
final @NotNull BukkitCommandActor actor,
final @NotNull Hologram hologram
) {
HologramTraitTrait traitTrait = hologram.getData().getTraitTrait();
if (traitTrait.getTraits().isEmpty()) {
translator.translate("commands.hologram.edit.trait.list.no_traits")
.replace("hologram", hologram.getData().getName())
.send(actor.sender());
return;
}
translator.translate("commands.hologram.edit.trait.list.header")
.replace("hologram", hologram.getData().getName())
.send(actor.sender());
for (HologramTrait trait : traitTrait.getTraits()) {
translator.translate("commands.hologram.edit.trait.list.entry")
.replace("name", trait.getName())
.send(actor.sender());
}
}
}

View File

@@ -212,6 +212,17 @@ public final class FancyHologramsPlugin extends JavaPlugin implements FancyHolog
if (!configuration.areVersionNotificationsMuted()) {
checkForNewerVersion();
}
if (versionConfig.isDevelopmentBuild()) {
fancyLogger.warn("""
--------------------------------------------------
You are using a development build of FancyHolograms.
Please be aware that there might be bugs in this version.
If you find any bugs, please report them on our discord server (https://discord.gg/ZUgYCEJUEx).
Read more about the risks of using a development build here: https://docs.fancyinnovations.com/development-guidelines/versioning/#build
--------------------------------------------------
""");
}
metrics.register();
metrics.registerLegacy();
@@ -300,7 +311,7 @@ public final class FancyHologramsPlugin extends JavaPlugin implements FancyHolog
getServer().getPluginManager().registerEvents(new PlayerListener(this), this);
getServer().getPluginManager().registerEvents(new WorldLoadedListener(), this);
if (Bukkit.getMinecraftVersion().equals("1.21.4") || Bukkit.getMinecraftVersion().equals("1.21.5") || Bukkit.getMinecraftVersion().equals("1.21.6")) {
if (Set.of("1.21.4", "1.21.5", "1.21.6").contains(Bukkit.getMinecraftVersion())) {
getServer().getPluginManager().registerEvents(new PlayerLoadedListener(), this);
}

View File

@@ -1,6 +1,7 @@
package com.fancyinnovations.fancyholograms.metrics;
import com.fancyinnovations.fancyholograms.api.HologramRegistry;
import com.fancyinnovations.fancyholograms.api.hologram.Hologram;
import com.fancyinnovations.fancyholograms.main.FancyHologramsPlugin;
import de.oliver.fancyanalytics.api.FancyAnalyticsAPI;
import de.oliver.fancyanalytics.api.metrics.MetricSupplier;
@@ -74,6 +75,14 @@ public class FHMetrics {
.toArray(String[]::new);
}));
fancyAnalytics.registerNumberMetric(new MetricSupplier<>("total_amount_attached_traits", () -> {
double total = 0d;
for (Hologram hologram : registry.getAll()) {
total += hologram.getData().getTraitTrait().getTraits().size();
}
return total;
}));
fancyAnalytics.initialize();
}

View File

@@ -21,3 +21,7 @@ messages:
detach:
not_attached: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> does not have trait {warningColor}{name}<gray> attached."
success: "<dark_gray> <gray>Successfully detached trait {warningColor}{name}<gray> from hologram {warningColor}{hologram}<gray>."
list:
no_traits: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> does not have any traits attached."
header: "<dark_gray> <gray>Hologram {warningColor}{hologram}<gray> has the following traits attached:"
entry: "<dark_gray> <gray> - {warningColor}{name}<gray>"

View File

@@ -1,6 +1,6 @@
- Added support for MiniPlaceholders v3
- Added permissions for each action type
- Improved logging
- Fixed various bugs for the player-npcs fflag
- Added an optional flag to disable arm swinging in Npc#update
- Added NpcManager#isLoaded method
- Added support for 1.21.11
- Fixed skin mirroring for 1.21.9
- Added inverted permission check for `need_permission` action (use prefix `!` to invert)
- Added `/npc rotate <npc> <yaw> <pitch>` command to set NPC orientation
- Added `swing_arm_on_update` config option
- Added `use-minecraft-usercache` feature flag

View File

@@ -35,7 +35,7 @@ Check out **[images section](#images)** down below.
## Installation
Paper **1.19.4** - **1.21.8** with **Java 21** (or higher) is required. Plugin should also work on **Paper** forks.
Paper **1.19.4** - **1.21.11** with **Java 21** (or higher) is required. Plugin should also work on **Paper** forks.
**Spigot** is **not** supported.

View File

@@ -1 +1 @@
2.7.1.299
2.8.0.308

View File

@@ -6,35 +6,10 @@ plugins {
id("xyz.jpenilla.run-paper")
id("com.gradleup.shadow")
id("de.eldoria.plugin-yml.paper")
id("io.papermc.hangar-publish-plugin")
id("com.modrinth.minotaur")
}
runPaper.folia.registerTask()
val supportedVersions =
listOf(
"1.19.4",
"1.20",
"1.20.1",
"1.20.2",
"1.20.3",
"1.20.4",
"1.20.5",
"1.20.6",
"1.21",
"1.21.1",
"1.21.2",
"1.21.3",
"1.21.4",
"1.21.5",
"1.21.6",
"1.21.7",
"1.21.8",
"1.21.9",
"1.21.10"
)
allprojects {
group = "de.oliver"
version = getFNVersion()
@@ -53,9 +28,10 @@ allprojects {
}
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.9-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
implementation(project(":plugins:fancynpcs:fn-api"))
implementation(project(":plugins:fancynpcs:implementation_1_21_11"))
implementation(project(":plugins:fancynpcs:implementation_1_21_9"))
implementation(project(":plugins:fancynpcs:implementation_1_21_6"))
implementation(project(":plugins:fancynpcs:implementation_1_21_5"))
@@ -78,12 +54,12 @@ dependencies {
implementation(project(":libraries:jdb"))
implementation(project(":libraries:plugin-tests"))
implementation(project(":libraries:config"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
implementation("de.oliver.FancyAnalytics:java-sdk:0.0.4")
implementation("de.oliver.FancyAnalytics:mc-api:0.1.11")
implementation("de.oliver.FancyAnalytics:logger:0.0.8")
implementation("org.incendo:cloud-core:2.0.0")
implementation("org.incendo:cloud-paper:2.0.0-beta.11")
implementation("org.incendo:cloud-paper:2.0.0-beta.13")
implementation("org.incendo:cloud-annotations:2.0.0")
annotationProcessor("org.incendo:cloud-annotations:2.0.0")
implementation("org.mineskin:java-client-jsoup:3.0.3-SNAPSHOT")
@@ -120,7 +96,7 @@ paper {
tasks {
runServer {
minecraftVersion("1.21.9")
minecraftVersion("1.21.10")
downloadPlugins {
// hangar("ViaVersion", "5.4.0")
@@ -204,14 +180,6 @@ tasks {
}
}
tasks.publishAllPublicationsToHangar {
dependsOn(":plugins:fancynpcs:shadowJar")
}
tasks.modrinth {
dependsOn(":plugins:fancynpcs:shadowJar")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
@@ -227,34 +195,3 @@ val gitCommitMessage: Provider<String> = providers.exec {
fun getFNVersion(): String {
return file("VERSION").readText()
}
hangarPublish {
publications.register("plugin") {
version = getFNVersion()
id = "FancyNpcs"
channel = "Alpha"
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
platforms {
paper {
jar = tasks.shadowJar.flatMap { it.archiveFile }
platformVersions.set(supportedVersions)
}
}
changelog = gitCommitMessage.get()
}
}
modrinth {
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
projectId.set("fancynpcs")
versionNumber.set(getFNVersion())
versionType.set("alpha")
uploadFile.set(file("build/libs/${project.name}-${getFNVersion()}.jar"))
gameVersions.addAll(supportedVersions)
loaders.add("paper")
loaders.add("folia")
changelog.set(gitCommitMessage.get())
}

View File

@@ -13,7 +13,7 @@ dependencies {
compileOnly(project(":libraries:config"))
compileOnly("de.oliver.FancyAnalytics:logger:0.0.8")
implementation("org.lushplugins:ChatColorHandler:6.0.2")
implementation("org.lushplugins:ChatColorHandler:6.0.0")
}
tasks {

View File

@@ -35,6 +35,8 @@ public interface FancyNpcsConfig {
int getRemoveNpcsFromPlayerlistDelay();
boolean isSwingArmOnUpdate();
String getMineSkinApiKey();
List<String> getBlockedCommands();

View File

@@ -132,7 +132,7 @@ public abstract class Npc {
public abstract void update(Player player, boolean swingArm);
public void update(Player player) {
update(player, true);
update(player, FancyNpcsPlugin.get().getFancyNpcConfig().isSwingArmOnUpdate());
}
public void updateForAll(boolean swingArm) {
@@ -142,13 +142,13 @@ public abstract class Npc {
}
public void updateForAll() {
updateForAll(true);
updateForAll(FancyNpcsPlugin.get().getFancyNpcConfig().isSwingArmOnUpdate());
}
public abstract void move(Player player, boolean swingArm);
public void move(Player player) {
move(player, true);
move(player, FancyNpcsPlugin.get().getFancyNpcConfig().isSwingArmOnUpdate());
}
public void moveForAll(boolean swingArm) {
@@ -158,7 +158,7 @@ public abstract class Npc {
}
public void moveForAll() {
moveForAll(true);
moveForAll(FancyNpcsPlugin.get().getFancyNpcConfig().isSwingArmOnUpdate());
}
public void interact(Player player) {

View File

@@ -20,7 +20,13 @@ public class NeedPermissionAction extends NpcAction {
return;
}
if (!context.getPlayer().hasPermission(value)) {
boolean invertCheck = value.startsWith("!");
String permission = invertCheck ? value.substring(1) : value;
boolean hasPermission = context.getPlayer().hasPermission(permission);
boolean passesCheck = invertCheck ? !hasPermission : hasPermission;
if (!passesCheck) {
FancyNpcsPlugin.get().getTranslator().translate("action_missing_permissions").send(context.getPlayer());
context.terminate();
}

View File

@@ -90,6 +90,7 @@ public class NpcModifyEvent extends Event implements Cancellable {
LOCATION,
MIRROR_SKIN,
PLAYER_COMMAND,
ROTATION,
SERVER_COMMAND,
SHOW_IN_TAB,
SKIN,

View File

@@ -10,7 +10,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -10,7 +10,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -10,7 +10,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -10,7 +10,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -0,0 +1,27 @@
plugins {
id("java-library")
id("io.papermc.paperweight.userdev")
}
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION
dependencies {
paperweight.paperDevBundle("25w45a-R0.1-SNAPSHOT")
// compileOnly("com.fancyinnovations:fancymc:1.21.6-pre2")
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}
tasks {
javadoc {
options.encoding = Charsets.UTF_8.name()
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release = 21
}
}

View File

@@ -0,0 +1,31 @@
package de.oliver.fancynpcs.v1_21_11;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.server.level.ServerPlayer;
import java.util.function.Predicate;
public class FakeSynchronizer implements ServerEntity.Synchronizer {
public static final FakeSynchronizer INSTANCE = new FakeSynchronizer();
private FakeSynchronizer() {
}
@Override
public void sendToTrackingPlayers(Packet<? super ClientGamePacketListener> packet) {
}
@Override
public void sendToTrackingPlayersAndSelf(Packet<? super ClientGamePacketListener> packet) {
}
@Override
public void sendToTrackingPlayersFiltered(Packet<? super ClientGamePacketListener> packet, Predicate<ServerPlayer> predicate) {
}
}

View File

@@ -0,0 +1,459 @@
package de.oliver.fancynpcs.v1_21_11;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.mojang.authlib.properties.PropertyMap;
import com.mojang.datafixers.util.Pair;
import de.oliver.fancylib.ReflectionUtils;
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.api.NpcData;
import de.oliver.fancynpcs.api.events.NpcSpawnEvent;
import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.Optionull;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.RemoteChatSession;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.Identifier;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ServerEntity;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.Team;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import org.lushplugins.chatcolorhandler.ModernChatColorHandler;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Npc_1_21_11 extends Npc {
private final String localName;
private final UUID uuid;
private Entity npc;
private Display.TextDisplay sittingVehicle;
public Npc_1_21_11(NpcData data) {
super(data);
this.localName = generateLocalName();
this.uuid = UUID.randomUUID();
}
@Override
public void create() {
MinecraftServer minecraftServer = ((CraftServer) Bukkit.getServer()).getServer();
ServerLevel serverLevel = ((CraftWorld) data.getLocation().getWorld()).getHandle();
GameProfile gameProfile = new GameProfile(uuid, localName);
if (data.getType() == org.bukkit.entity.EntityType.PLAYER) {
npc = new ServerPlayer(minecraftServer, serverLevel, new GameProfile(uuid, ""), ClientInformation.createDefault());
((ServerPlayer) npc).gameProfile = gameProfile;
} else {
Optional<Holder.Reference<EntityType<?>>> entityTypeReference = BuiltInRegistries.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(data.getType().getKey()));
EntityType<?> nmsType = entityTypeReference.get().value(); // TODO handle empty
EntityType.EntityFactory factory = (EntityType.EntityFactory) ReflectionUtils.getValue(nmsType, "factory"); // EntityType.factory
npc = factory.create(nmsType, serverLevel);
isTeamCreated.clear();
}
}
@Override
public void spawn(Player player) {
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
if (npc == null) {
return;
}
if (!data.getLocation().getWorld().getName().equalsIgnoreCase(serverPlayer.level().getWorld().getName())) {
return;
}
if (data.getSkinData() != null && data.getSkinData().hasTexture()) {
String value = data.getSkinData().getTextureValue();
String signature = data.getSkinData().getTextureSignature();
PropertyMap propertyMap = new PropertyMap(
ImmutableMultimap.of(
"textures",
new Property("textures", value, signature)
)
);
((ServerPlayer) npc).gameProfile = new GameProfile(uuid, localName, propertyMap);
}
NpcSpawnEvent spawnEvent = new NpcSpawnEvent(this, player);
spawnEvent.callEvent();
if (spawnEvent.isCancelled()) {
return;
}
if (npc instanceof ServerPlayer npcPlayer) {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.noneOf(ClientboundPlayerInfoUpdatePacket.Action.class);
actions.add(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
actions.add(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
if (data.isShowInTab()) {
actions.add(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
}
ClientboundPlayerInfoUpdatePacket playerInfoPacket = new ClientboundPlayerInfoUpdatePacket(actions, getEntry(npcPlayer, serverPlayer));
serverPlayer.connection.send(playerInfoPacket);
if (data.isSpawnEntity()) {
npc.setPos(data.getLocation().x(), data.getLocation().y(), data.getLocation().z());
}
}
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(
npc.getId(),
npc.getUUID(),
data.getLocation().x(),
data.getLocation().y(),
data.getLocation().z(),
data.getLocation().getPitch(),
data.getLocation().getYaw(),
npc.getType(),
0,
Vec3.ZERO,
data.getLocation().getYaw()
);
serverPlayer.connection.send(addEntityPacket);
isVisibleForPlayer.put(player.getUniqueId(), true);
int removeNpcsFromPlayerlistDelay = FancyNpcsPlugin.get().getFancyNpcConfig().getRemoveNpcsFromPlayerlistDelay();
if (!data.isShowInTab() && removeNpcsFromPlayerlistDelay > 0) {
FancyNpcsPlugin.get().getNpcThread().schedule(() -> {
ClientboundPlayerInfoRemovePacket playerInfoRemovePacket = new ClientboundPlayerInfoRemovePacket(List.of(npc.getUUID()));
serverPlayer.connection.send(playerInfoRemovePacket);
}, removeNpcsFromPlayerlistDelay, TimeUnit.MILLISECONDS);
}
update(player);
}
@Override
public void remove(Player player) {
if (npc == null) {
return;
}
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
if (npc instanceof ServerPlayer npcPlayer) {
ClientboundPlayerInfoRemovePacket playerInfoRemovePacket = new ClientboundPlayerInfoRemovePacket(List.of((npcPlayer.getUUID())));
serverPlayer.connection.send(playerInfoRemovePacket);
}
// remove entity
ClientboundRemoveEntitiesPacket removeEntitiesPacket = new ClientboundRemoveEntitiesPacket(npc.getId());
serverPlayer.connection.send(removeEntitiesPacket);
// remove sitting vehicle
if (sittingVehicle != null) {
ClientboundRemoveEntitiesPacket removeSittingVehiclePacket = new ClientboundRemoveEntitiesPacket(sittingVehicle.getId());
serverPlayer.connection.send(removeSittingVehiclePacket);
}
isVisibleForPlayer.put(serverPlayer.getUUID(), false);
}
@Override
public void lookAt(Player player, Location location) {
if (npc == null) {
return;
}
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
npc.setRot(location.getYaw(), location.getPitch());
npc.setYHeadRot(location.getYaw());
npc.setXRot(location.getPitch());
npc.setYRot(location.getYaw());
ClientboundTeleportEntityPacket teleportEntityPacket = new ClientboundTeleportEntityPacket(
npc.getId(),
new PositionMoveRotation(
new Vec3(data.getLocation().getX(), data.getLocation().getY(), data.getLocation().getZ()),
Vec3.ZERO,
location.getYaw(),
location.getPitch()
),
Set.of(),
false
);
serverPlayer.connection.send(teleportEntityPacket);
float angelMultiplier = 256f / 360f;
ClientboundRotateHeadPacket rotateHeadPacket = new ClientboundRotateHeadPacket(npc, (byte) (location.getYaw() * angelMultiplier));
serverPlayer.connection.send(rotateHeadPacket);
}
@Override
public void update(Player player, boolean swingArm) {
if (npc == null) {
return;
}
if (!isVisibleForPlayer.getOrDefault(player.getUniqueId(), false)) {
return;
}
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
PlayerTeam team = new PlayerTeam(new Scoreboard(), "npc-" + localName);
team.getPlayers().clear();
team.getPlayers().add(npc instanceof ServerPlayer npcPlayer ? npcPlayer.getGameProfile().name() : npc.getStringUUID());
team.setColor(PaperAdventure.asVanilla(data.getGlowingColor()));
if (!data.isCollidable()) {
team.setCollisionRule(Team.CollisionRule.NEVER);
}
net.kyori.adventure.text.Component displayName = ModernChatColorHandler.translate(data.getDisplayName(), serverPlayer.getBukkitEntity());
Component vanillaComponent = PaperAdventure.asVanilla(displayName);
if (!(npc instanceof ServerPlayer)) {
npc.setCustomName(vanillaComponent);
npc.setCustomNameVisible(true);
} else {
npc.setCustomName(null);
npc.setCustomNameVisible(false);
}
if (data.getDisplayName().equalsIgnoreCase("<empty>")) {
team.setNameTagVisibility(Team.Visibility.NEVER);
npc.setCustomName(null);
npc.setCustomNameVisible(false);
} else {
team.setNameTagVisibility(Team.Visibility.ALWAYS);
}
if (npc instanceof ServerPlayer npcPlayer) {
team.setPlayerPrefix(vanillaComponent);
npcPlayer.listName = vanillaComponent;
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.noneOf(ClientboundPlayerInfoUpdatePacket.Action.class);
actions.add(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
if (data.isShowInTab()) {
actions.add(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
}
ClientboundPlayerInfoUpdatePacket playerInfoPacket = new ClientboundPlayerInfoUpdatePacket(actions, getEntry(npcPlayer, serverPlayer));
serverPlayer.connection.send(playerInfoPacket);
}
boolean isTeamCreatedForPlayer = this.isTeamCreated.getOrDefault(player.getUniqueId(), false);
serverPlayer.connection.send(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, !isTeamCreatedForPlayer));
isTeamCreated.put(player.getUniqueId(), true);
npc.setGlowingTag(data.isGlowing());
data.applyAllAttributes(this);
// Set equipment
List<Pair<EquipmentSlot, ItemStack>> equipmentList = new ArrayList<>();
if (data.getEquipment() != null) {
for (NpcEquipmentSlot slot : data.getEquipment().keySet()) {
equipmentList.add(new Pair<>(EquipmentSlot.byName(slot.toNmsName()), CraftItemStack.asNMSCopy(data.getEquipment().get(slot))));
}
}
// Set body slot (from happy ghast harness attribute)
if (npc instanceof LivingEntity livingEntity) {
ItemStack bodySlot = livingEntity.getItemBySlot(EquipmentSlot.BODY);
if (!bodySlot.isEmpty()) {
equipmentList.add(new Pair<>(EquipmentSlot.BODY, bodySlot));
}
}
if (!equipmentList.isEmpty()) {
ClientboundSetEquipmentPacket setEquipmentPacket = new ClientboundSetEquipmentPacket(npc.getId(), equipmentList);
serverPlayer.connection.send(setEquipmentPacket);
}
if (npc instanceof ServerPlayer) {
// Enable second layer of skin (https://wiki.vg/Entity_metadata#Player)
npc.getEntityData().set(net.minecraft.world.entity.player.Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) (0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40));
}
refreshEntityData(player);
if (data.isSpawnEntity() && data.getLocation() != null) {
move(player, swingArm);
}
NpcAttribute playerPoseAttr = FancyNpcsPlugin.get().getAttributeManager().getAttributeByName(org.bukkit.entity.EntityType.PLAYER, "pose");
if (data.getAttributes().containsKey(playerPoseAttr)) {
String pose = data.getAttributes().get(playerPoseAttr);
if (pose.equals("sitting")) {
setSitting(serverPlayer);
} else {
if (sittingVehicle != null) {
ClientboundRemoveEntitiesPacket removeSittingVehiclePacket = new ClientboundRemoveEntitiesPacket(sittingVehicle.getId());
serverPlayer.connection.send(removeSittingVehiclePacket);
}
}
}
if (npc instanceof LivingEntity) {
Holder.Reference<Attribute> scaleAttribute = BuiltInRegistries.ATTRIBUTE.get(Identifier.parse("minecraft:scale")).get();
AttributeInstance attributeInstance = new AttributeInstance(scaleAttribute, (a) -> {
});
attributeInstance.setBaseValue(data.getScale());
ClientboundUpdateAttributesPacket updateAttributesPacket = new ClientboundUpdateAttributesPacket(npc.getId(), List.of(attributeInstance));
serverPlayer.connection.send(updateAttributesPacket);
}
}
@Override
protected void refreshEntityData(Player player) {
if (!isVisibleForPlayer.getOrDefault(player.getUniqueId(), false)) {
return;
}
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
SynchedEntityData.DataItem<?>[] itemsById = (SynchedEntityData.DataItem<?>[]) ReflectionUtils.getValue(npc.getEntityData(), "itemsById"); // itemsById
List<SynchedEntityData.DataValue<?>> entityData = new ArrayList<>();
for (SynchedEntityData.DataItem<?> dataItem : itemsById) {
entityData.add(dataItem.value());
}
ClientboundSetEntityDataPacket setEntityDataPacket = new ClientboundSetEntityDataPacket(npc.getId(), entityData);
serverPlayer.connection.send(setEntityDataPacket);
}
public void move(Player player, boolean swingArm) {
if (npc == null) {
return;
}
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
npc.setPosRaw(data.getLocation().x(), data.getLocation().y(), data.getLocation().z());
npc.setRot(data.getLocation().getYaw(), data.getLocation().getPitch());
npc.setYHeadRot(data.getLocation().getYaw());
npc.setXRot(data.getLocation().getPitch());
npc.setYRot(data.getLocation().getYaw());
ClientboundTeleportEntityPacket teleportEntityPacket = new ClientboundTeleportEntityPacket(
npc.getId(),
new PositionMoveRotation(
new Vec3(data.getLocation().getX(), data.getLocation().getY(), data.getLocation().getZ()),
Vec3.ZERO,
data.getLocation().getYaw(),
data.getLocation().getPitch()
),
Set.of(),
false
);
serverPlayer.connection.send(teleportEntityPacket);
float angelMultiplier = 256f / 360f;
ClientboundRotateHeadPacket rotateHeadPacket = new ClientboundRotateHeadPacket(npc, (byte) (data.getLocation().getYaw() * angelMultiplier));
serverPlayer.connection.send(rotateHeadPacket);
if (swingArm && npc instanceof ServerPlayer) {
ClientboundAnimatePacket animatePacket = new ClientboundAnimatePacket(npc, 0);
serverPlayer.connection.send(animatePacket);
}
}
private ClientboundPlayerInfoUpdatePacket.Entry getEntry(ServerPlayer npcPlayer, ServerPlayer viewer) {
GameProfile profile;
if (!data.isMirrorSkin()) {
profile = npcPlayer.getGameProfile();
} else {
Property textures = viewer.getGameProfile().properties().get("textures").iterator().next();
PropertyMap propertyMap = new PropertyMap(
ImmutableMultimap.of(
"textures",
new Property("textures", textures.value(), textures.signature())
)
);
profile = new GameProfile(uuid, localName, propertyMap);
}
return new ClientboundPlayerInfoUpdatePacket.Entry(
npcPlayer.getUUID(),
profile,
data.isShowInTab(),
0,
npcPlayer.gameMode.getGameModeForPlayer(),
npcPlayer.getTabListDisplayName(),
true,
-1,
Optionull.map(npcPlayer.getChatSession(), RemoteChatSession::asData)
);
}
public void setSitting(ServerPlayer serverPlayer) {
if (npc == null) {
return;
}
if (sittingVehicle == null) {
sittingVehicle = new Display.TextDisplay(EntityType.TEXT_DISPLAY, ((CraftWorld) data.getLocation().getWorld()).getHandle());
}
sittingVehicle.setPos(data.getLocation().x(), data.getLocation().y(), data.getLocation().z());
ServerEntity serverEntity = new ServerEntity(
serverPlayer.level(),
sittingVehicle,
0,
false,
FakeSynchronizer.INSTANCE,
Set.of()
);
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(sittingVehicle, serverEntity);
serverPlayer.connection.send(addEntityPacket);
sittingVehicle.passengers = ImmutableList.of(npc);
ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(sittingVehicle);
serverPlayer.connection.send(packet);
}
@Override
public float getEyeHeight() {
return npc.getEyeHeight();
}
@Override
public int getEntityId() {
return npc.getId();
}
public Entity getNpc() {
return npc;
}
}

View File

@@ -0,0 +1,13 @@
package de.oliver.fancynpcs.v1_21_11;
import de.oliver.fancylib.ReflectionUtils;
import de.oliver.fancynpcs.api.Npc;
import net.minecraft.world.entity.Entity;
public class ReflectionHelper {
public static <T extends Entity> T getEntity(Npc npc) {
return (T) ReflectionUtils.getValue(npc, "npc");
}
}

View File

@@ -0,0 +1,38 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.AgeableMob;
import org.bukkit.entity.Ageable;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AgeableMobAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"baby",
List.of("true", "false"),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && Ageable.class.isAssignableFrom(type.getEntityClass()))
.toList(),
AgeableMobAttributes::setBaby
));
return attributes;
}
private static void setBaby(Npc npc, String value) {
AgeableMob mob = ReflectionHelper.getEntity(npc);
boolean isBaby = Boolean.parseBoolean(value);
mob.setBaby(isBaby);
}
}

View File

@@ -0,0 +1,34 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.allay.Allay;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class AllayAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"dancing",
List.of("true", "false"),
List.of(EntityType.ALLAY),
AllayAttributes::setDancing
));
return attributes;
}
private static void setDancing(Npc npc, String value) {
Allay allay = ReflectionHelper.getEntity(npc);
boolean dancing = Boolean.parseBoolean(value);
allay.setDancing(dancing);
}
}

View File

@@ -0,0 +1,35 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.armadillo.Armadillo;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class ArmadilloAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"pose",
List.of("idle", "rolling", "unrolling", "scared"),
List.of(EntityType.ARMADILLO),
ArmadilloAttributes::setPose
));
return attributes;
}
private static void setPose(Npc npc, String value) {
Armadillo armadillo = ReflectionHelper.getEntity(npc);
Armadillo.ArmadilloState state = Armadillo.ArmadilloState.valueOf(value.toUpperCase());
armadillo.switchToState(state);
}
}

View File

@@ -0,0 +1,35 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.decoration.ArmorStand;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class ArmorStandAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"show_arms",
List.of("true", "false"),
List.of(EntityType.ARMOR_STAND),
ArmorStandAttributes::setShowArms
));
return attributes;
}
private static void setShowArms(Npc npc, String value) {
ArmorStand armorStand = ReflectionHelper.getEntity(npc);
boolean showArms = Boolean.parseBoolean(value.toLowerCase());
armorStand.setShowArms(showArms);
}
}

View File

@@ -0,0 +1,56 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.NpcAttribute;
import java.util.ArrayList;
import java.util.List;
public class Attributes_1_21_11 {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.addAll(EntityAttributes.getAllAttributes());
attributes.addAll(LivingEntityAttributes.getAllAttributes());
attributes.addAll(AgeableMobAttributes.getAllAttributes());
attributes.addAll(IllagerAttributes.getAllAttributes());
attributes.addAll(SpellCasterAttributes.getAllAttributes());
attributes.addAll(PlayerAttributes.getAllAttributes());
attributes.addAll(SheepAttributes.getAllAttributes());
attributes.addAll(VillagerAttributes.getAllAttributes());
attributes.addAll(FrogAttributes.getAllAttributes());
attributes.addAll(HorseAttributes.getAllAttributes());
attributes.addAll(ParrotAttributes.getAllAttributes());
attributes.addAll(AxolotlAttributes.getAllAttributes());
attributes.addAll(TropicalFishAttributes.getAllAttributes());
attributes.addAll(FoxAttributes.getAllAttributes());
attributes.addAll(PandaAttributes.getAllAttributes());
attributes.addAll(GoatAttributes.getAllAttributes());
attributes.addAll(AllayAttributes.getAllAttributes());
attributes.addAll(CamelAttributes.getAllAttributes());
attributes.addAll(RabbitAttributes.getAllAttributes());
attributes.addAll(PiglinAttributes.getAllAttributes());
attributes.addAll(CatAttributes.getAllAttributes());
attributes.addAll(ShulkerAttributes.getAllAttributes());
attributes.addAll(WolfAttributes.getAllAttributes());
attributes.addAll(SlimeAttributes.getAllAttributes());
attributes.addAll(PigAttributes.getAllAttributes());
attributes.addAll(CowAttributes.getAllAttributes());
attributes.addAll(ChickenAttributes.getAllAttributes());
attributes.addAll(ArmorStandAttributes.getAllAttributes());
attributes.addAll(BeeAttributes.getAllAttributes());
attributes.addAll(VexAttributes.getAllAttributes());
attributes.addAll(ArmadilloAttributes.getAllAttributes());
attributes.addAll(HappyGhastAttributes.getAllAttributes());
attributes.addAll(SnifferAttributes.getAllAttributes());
attributes.addAll(DisplayAttributes.getAllAttributes());
attributes.addAll(TextDisplayAttributes.getAllAttributes());
attributes.addAll(BlockDisplayAttributes.getAllAttributes());
attributes.addAll(InteractionAttributes.getAllAttributes());
return attributes;
}
}

View File

@@ -0,0 +1,51 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.axolotl.Axolotl;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AxolotlAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
Arrays.stream(Axolotl.Variant.values())
.map(Enum::name)
.toList(),
List.of(EntityType.AXOLOTL),
AxolotlAttributes::setVariant
));
attributes.add(new NpcAttribute(
"playing_dead",
List.of("true", "false"),
List.of(EntityType.AXOLOTL),
AxolotlAttributes::setPlayingDead
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
Axolotl axolotl = ReflectionHelper.getEntity(npc);
Axolotl.Variant variant = Axolotl.Variant.valueOf(value.toUpperCase());
axolotl.setVariant(variant);
}
private static void setPlayingDead(Npc npc, String value) {
Axolotl axolotl = ReflectionHelper.getEntity(npc);
boolean playingDead = Boolean.parseBoolean(value);
axolotl.setPlayingDead(playingDead);
}
}

View File

@@ -0,0 +1,84 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.Bee;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class BeeAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"angry",
List.of("true", "false"),
List.of(EntityType.BEE),
BeeAttributes::setAngry
));
attributes.add(new NpcAttribute(
"sting",
List.of("true", "false"),
List.of(EntityType.BEE),
BeeAttributes::setSting
));
attributes.add(new NpcAttribute(
"nectar",
List.of("true", "false"),
List.of(EntityType.BEE),
BeeAttributes::setNectar
));
attributes.add(new NpcAttribute(
"rolling",
List.of("true", "false"),
List.of(EntityType.BEE),
BeeAttributes::setRolling
));
return attributes;
}
private static void setAngry(Npc npc, String value) {
Bee bee = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "true" -> bee.setPersistentAngerEndTime(1);
case "false" -> bee.setPersistentAngerEndTime(0);
}
}
private static void setSting(Npc npc, String value) {
Bee bee = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "true" -> bee.setHasStung(false);
case "false" -> bee.setHasStung(true);
}
}
private static void setNectar(Npc npc, String value) {
Bee bee = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "true" -> bee.setHasNectar(true);
case "false" -> bee.setHasNectar(false);
}
}
private static void setRolling(Npc npc, String value) {
Bee bee = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "true" -> bee.setRolling(true);
case "false" -> bee.setRolling(false);
}
}
}

View File

@@ -0,0 +1,41 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.Display;
import net.minecraft.world.level.block.Block;
import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class BlockDisplayAttributes {
private static final List<String> BLOCKS = Registry.MATERIAL.stream().filter(Material::isBlock).map(it -> it.key().value()).toList();
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"block",
BLOCKS,
List.of(EntityType.BLOCK_DISPLAY),
BlockDisplayAttributes::setBlock
));
return attributes;
}
private static void setBlock(Npc npc, String value) {
Display.BlockDisplay display = ReflectionHelper.getEntity(npc);
Block block = BuiltInRegistries.BLOCK.getValue(Identifier.parse(value.toLowerCase()));
display.setBlockState(block.defaultBlockState());
}
}

View File

@@ -0,0 +1,54 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.animal.camel.Camel;
import org.bukkit.Bukkit;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class CamelAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sitting", "dashing"),
List.of(EntityType.CAMEL),
CamelAttributes::setPose
));
return attributes;
}
private static void setPose(Npc npc, String value) {
Camel camel = ReflectionHelper.getEntity(npc);
Bukkit.getScheduler().runTask(FancyNpcsPlugin.get().getPlugin(), () -> {
switch (value.toLowerCase()) {
case "standing" -> {
camel.setPose(Pose.STANDING);
camel.setDashing(false);
camel.resetLastPoseChangeTick(camel.level().getGameTime());
}
case "sitting" -> {
camel.setPose(Pose.SITTING);
camel.setDashing(false);
camel.resetLastPoseChangeTick(-camel.level().getGameTime());
}
case "dashing" -> {
camel.setPose(Pose.STANDING);
camel.setDashing(true);
camel.resetLastPoseChangeTick(camel.level().getGameTime());
}
}
});
}
}

View File

@@ -0,0 +1,107 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.animal.Cat;
import net.minecraft.world.entity.animal.CatVariant;
import net.minecraft.world.item.DyeColor;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class CatAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
getCatVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.CAT),
CatAttributes::setVariant
));
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sleeping", "sitting"),
List.of(EntityType.CAT),
CatAttributes::setPose
));
attributes.add(new NpcAttribute(
"collar_color",
List.of("RED", "BLUE", "YELLOW", "GREEN", "PURPLE", "ORANGE", "LIME", "MAGENTA", "BROWN", "WHITE", "GRAY", "LIGHT_GRAY", "LIGHT_BLUE", "BLACK", "CYAN", "PINK", "NONE"),
List.of(EntityType.CAT),
CatAttributes::setCollarColor
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
final Cat cat = ReflectionHelper.getEntity(npc);
Holder<CatVariant> variant = getCatVariantRegistry()
.get(ResourceKey.create(
Registries.CAT_VARIANT,
Identifier.withDefaultNamespace(value.toLowerCase())
))
.orElseThrow();
cat.setVariant(variant);
}
private static void setPose(Npc npc, String value) {
final Cat cat = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> {
cat.setInSittingPose(false, false);
cat.setLying(false);
}
case "sleeping" -> {
cat.setInSittingPose(false, false);
cat.setLying(true);
}
case "sitting" -> {
cat.setLying(false);
cat.setOrderedToSit(true);
cat.setInSittingPose(true, false);
}
}
}
private static HolderLookup.RegistryLookup<CatVariant> getCatVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.CAT_VARIANT);
}
private static void setCollarColor(Npc npc, String value) {
Cat cat = ReflectionHelper.getEntity(npc);
if (value.equalsIgnoreCase("none") || value.isEmpty()) {
// Reset to no collar
cat.setTame(false, false);
return;
}
try {
DyeColor color = DyeColor.valueOf(value.toUpperCase());
if (!cat.isTame()) {
cat.setTame(true, false);
}
cat.setCollarColor(color);
} catch (IllegalArgumentException e) {
System.out.println("Invalid cat collar color: " + value);
}
}
}

View File

@@ -0,0 +1,54 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.animal.Chicken;
import net.minecraft.world.entity.animal.ChickenVariant;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class ChickenAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
getChickenVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.CHICKEN),
ChickenAttributes::setVariant
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
final Chicken cow = ReflectionHelper.getEntity(npc);
Holder<ChickenVariant> variant = getChickenVariantRegistry()
.get(ResourceKey.create(
Registries.CHICKEN_VARIANT,
Identifier.withDefaultNamespace(value.toLowerCase())
))
.orElseThrow();
cow.setVariant(variant);
}
private static HolderLookup.RegistryLookup<ChickenVariant> getChickenVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.CHICKEN_VARIANT);
}
}

View File

@@ -0,0 +1,54 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.animal.Cow;
import net.minecraft.world.entity.animal.CowVariant;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class CowAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
getCowVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.COW),
CowAttributes::setVariant
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
final Cow cow = ReflectionHelper.getEntity(npc);
Holder<CowVariant> variant = getCowVariantRegistry()
.get(ResourceKey.create(
Registries.COW_VARIANT,
Identifier.withDefaultNamespace(value.toLowerCase())
))
.orElseThrow();
cow.setVariant(variant);
}
private static HolderLookup.RegistryLookup<CowVariant> getCowVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.COW_VARIANT);
}
}

View File

@@ -0,0 +1,37 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.Display;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DisplayAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"billboard",
Arrays.stream(org.bukkit.entity.Display.Billboard.values())
.map(Enum::name)
.toList(),
List.of(EntityType.TEXT_DISPLAY, EntityType.BLOCK_DISPLAY, EntityType.ITEM_DISPLAY),
DisplayAttributes::setBillboard
));
return attributes;
}
private static void setBillboard(Npc npc, String value) {
Display display = ReflectionHelper.getEntity(npc);
Display.BillboardConstraints billboard = Display.BillboardConstraints.valueOf(value.toUpperCase());
display.setBillboardConstraints(billboard);
}
}

View File

@@ -0,0 +1,103 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.Entity;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EntityAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"on_fire",
List.of("true", "false"),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setOnFire
));
attributes.add(new NpcAttribute(
"invisible",
List.of("true", "false"),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setInvisible
));
attributes.add(new NpcAttribute(
"silent",
List.of("true", "false"),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setSilent
));
attributes.add(new NpcAttribute(
"shaking",
List.of("true", "false"),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setShaking
));
attributes.add(new NpcAttribute(
"on_ground",
List.of("true", "false"),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setOnGround
));
/*attributes.add(new NpcAttribute(
"entity_pose",
Arrays.stream(Pose.values()).map(Enum::toString).toList(),
Arrays.stream(EntityType.values()).toList(),
EntityAttributes::setEntityPose
));*/
return attributes;
}
private static void setOnFire(Npc npc, String value) {
Entity entity = ReflectionHelper.getEntity(npc);
boolean onFire = Boolean.parseBoolean(value);
entity.setSharedFlagOnFire(onFire);
}
private static void setInvisible(Npc npc, String value) {
Entity entity = ReflectionHelper.getEntity(npc);
boolean invisible = Boolean.parseBoolean(value);
entity.setInvisible(invisible);
}
private static void setSilent(Npc npc, String value) {
Entity entity = ReflectionHelper.getEntity(npc);
boolean silent = Boolean.parseBoolean(value);
entity.setSilent(silent);
}
private static void setShaking(Npc npc, String value) {
Entity entity = ReflectionHelper.getEntity(npc);
boolean shaking = Boolean.parseBoolean(value);
entity.setTicksFrozen(shaking ? entity.getTicksRequiredToFreeze() : 0);
}
private static void setOnGround(Npc npc, String value) {
Entity entity = ReflectionHelper.getEntity(npc);
boolean onGround = Boolean.parseBoolean(value);
entity.setOnGround(onGround);
}
}

View File

@@ -0,0 +1,66 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.Fox;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FoxAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"type",
Arrays.stream(Fox.Variant.values())
.map(Enum::name)
.toList(),
List.of(EntityType.FOX),
FoxAttributes::setType
));
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sleeping", "sitting"),
List.of(EntityType.FOX),
FoxAttributes::setPose
));
return attributes;
}
private static void setType(Npc npc, String value) {
Fox fox = ReflectionHelper.getEntity(npc);
Fox.Variant type = Fox.Variant.valueOf(value.toUpperCase());
fox.setVariant(type);
}
private static void setPose(Npc npc, String value) {
Fox fox = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> {
fox.setIsCrouching(false);
fox.setSleeping(false);
fox.setSitting(false, false);
}
case "sleeping" -> {
fox.setSleeping(true);
fox.setSitting(false, false);
fox.setIsCrouching(false);
}
case "sitting" -> {
fox.setSitting(true, false);
fox.setSleeping(false);
fox.setIsCrouching(false);
}
}
}
}

View File

@@ -0,0 +1,53 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.animal.frog.Frog;
import net.minecraft.world.entity.animal.frog.FrogVariant;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class FrogAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
getFrogVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.FROG),
FrogAttributes::setVariant
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
final Frog frog = ReflectionHelper.getEntity(npc);
Holder<FrogVariant> variant = getFrogVariantRegistry()
.get(ResourceKey.create(
Registries.FROG_VARIANT,
Identifier.withDefaultNamespace(value.toLowerCase())
))
.orElseThrow();
frog.setVariant(variant);
}
private static HolderLookup.RegistryLookup<FrogVariant> getFrogVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.FROG_VARIANT);
}
}

View File

@@ -0,0 +1,44 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.goat.Goat;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class GoatAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"horns",
List.of("none", "left", "right", "both"),
List.of(EntityType.GOAT),
GoatAttributes::setHorns
));
return attributes;
}
private static void setHorns(Npc npc, String value) {
Goat goat = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "none" -> goat.removeHorns();
case "both" -> goat.addHorns();
case "left" -> {
goat.getEntityData().set(Goat.DATA_HAS_LEFT_HORN, true);
goat.getEntityData().set(Goat.DATA_HAS_RIGHT_HORN, false);
}
case "right" -> {
goat.getEntityData().set(Goat.DATA_HAS_RIGHT_HORN, true);
goat.getEntityData().set(Goat.DATA_HAS_LEFT_HORN, false);
}
}
}
}

View File

@@ -0,0 +1,57 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.animal.HappyGhast;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class HappyGhastAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"harness",
List.of("white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"),
List.of(EntityType.HAPPY_GHAST),
HappyGhastAttributes::setHarness
));
return attributes;
}
private static void setHarness(Npc npc, String value) {
HappyGhast ghast = ReflectionHelper.getEntity(npc);
ItemStack harnessItem = switch (value.toLowerCase()) {
case "white" -> Items.WHITE_HARNESS.getDefaultInstance();
case "orange" -> Items.ORANGE_HARNESS.getDefaultInstance();
case "magenta" -> Items.MAGENTA_HARNESS.getDefaultInstance();
case "light_blue" -> Items.LIGHT_BLUE_HARNESS.getDefaultInstance();
case "yellow" -> Items.YELLOW_HARNESS.getDefaultInstance();
case "lime" -> Items.LIME_HARNESS.getDefaultInstance();
case "pink" -> Items.PINK_HARNESS.getDefaultInstance();
case "gray" -> Items.GRAY_HARNESS.getDefaultInstance();
case "light_gray" -> Items.LIGHT_GRAY_HARNESS.getDefaultInstance();
case "cyan" -> Items.CYAN_HARNESS.getDefaultInstance();
case "purple" -> Items.PURPLE_HARNESS.getDefaultInstance();
case "blue" -> Items.BLUE_HARNESS.getDefaultInstance();
case "brown" -> Items.BROWN_HARNESS.getDefaultInstance();
case "green" -> Items.GREEN_HARNESS.getDefaultInstance();
case "red" -> Items.RED_HARNESS.getDefaultInstance();
case "black" -> Items.BLACK_HARNESS.getDefaultInstance();
default -> Items.AIR.getDefaultInstance();
};
if (!harnessItem.isEmpty()) {
ghast.setItemSlot(EquipmentSlot.BODY, harnessItem);
}
}
}

View File

@@ -0,0 +1,84 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.horse.Horse;
import net.minecraft.world.entity.animal.horse.Markings;
import net.minecraft.world.entity.animal.horse.Variant;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HorseAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
Arrays.stream(Variant.values())
.map(Enum::name)
.toList(),
List.of(EntityType.HORSE),
HorseAttributes::setVariant
));
attributes.add(new NpcAttribute(
"markings",
Arrays.stream(Markings.values())
.map(Enum::name)
.toList(),
List.of(EntityType.HORSE),
HorseAttributes::setMarkings
));
attributes.add(new NpcAttribute(
"pose",
List.of("eating", "rearing", "standing"),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && (type == EntityType.HORSE || type == EntityType.DONKEY ||
type == EntityType.MULE || type == EntityType.SKELETON_HORSE || type == EntityType.ZOMBIE_HORSE))
.toList(),
HorseAttributes::setPose
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
Horse horse = ReflectionHelper.getEntity(npc);
Variant variant = Variant.valueOf(value.toUpperCase());
horse.setVariantAndMarkings(variant, horse.getMarkings());
}
private static void setMarkings(Npc npc, String value) {
Horse horse = ReflectionHelper.getEntity(npc);
Markings markings = Markings.valueOf(value.toUpperCase());
horse.setVariantAndMarkings(horse.getVariant(), markings);
}
private static void setPose(Npc npc, String value) {
net.minecraft.world.entity.animal.horse.AbstractHorse horse = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> {
horse.setEating(false);
horse.setStanding(0);
}
case "rearing" -> {
horse.setStanding(20);
horse.setEating(false);
}
case "eating" -> {
horse.setStanding(0);
horse.setEating(true);
}
}
}
}

View File

@@ -0,0 +1,39 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.raid.Raider;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Illager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class IllagerAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"celebrating",
List.of("true", "false"),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && Illager.class.isAssignableFrom(type.getEntityClass()))
.toList(),
IllagerAttributes::setCelebrating
));
return attributes;
}
private static void setCelebrating(Npc npc, String value) {
Raider raider = ReflectionHelper.getEntity(npc);
boolean isCelebrating = Boolean.parseBoolean(value);
raider.setCelebrating(isCelebrating);
}
}

View File

@@ -0,0 +1,60 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.Interaction;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class InteractionAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"height",
new ArrayList<>(),
List.of(EntityType.INTERACTION),
InteractionAttributes::setHeight
));
attributes.add(new NpcAttribute(
"width",
new ArrayList<>(),
List.of(EntityType.INTERACTION),
InteractionAttributes::setWidth
));
return attributes;
}
private static void setHeight(Npc npc, String value) {
Interaction interaction = ReflectionHelper.getEntity(npc);
float height;
try {
height = Float.parseFloat(value);
} catch (NumberFormatException e) {
return;
}
interaction.setHeight(height);
}
private static void setWidth(Npc npc, String value) {
Interaction interaction = ReflectionHelper.getEntity(npc);
float width;
try {
width = Float.parseFloat(value);
} catch (NumberFormatException e) {
return;
}
interaction.setWidth(width);
}
}

View File

@@ -0,0 +1,67 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.InteractionHand;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LivingEntityAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
/*attributes.add(new NpcAttribute(
"hurt",
List.of("true", "false"),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()))
.toList(),
LivingEntityAttributes::setHurt
));*/
attributes.add(new NpcAttribute(
"use_item",
List.of("main_hand", "off_hand", "none"),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && LivingEntity.class.isAssignableFrom(type.getEntityClass()))
.toList(),
LivingEntityAttributes::setUseItem
));
return attributes;
}
private static void setHurt(Npc npc, String value) {
net.minecraft.world.entity.LivingEntity livingEntity = ReflectionHelper.getEntity(npc);
boolean isHurt = Boolean.parseBoolean(value);
if (isHurt) {
livingEntity.hurtDuration = 1;
livingEntity.hurtTime = 1;
livingEntity.hurtMarked = true;
livingEntity.animateHurt(0);
} else {
livingEntity.hurtDuration = 0;
livingEntity.hurtTime = 0;
livingEntity.hurtMarked = false;
}
}
private static void setUseItem(Npc npc, String value) {
net.minecraft.world.entity.LivingEntity livingEntity = ReflectionHelper.getEntity(npc);
switch (value.toUpperCase()) {
case "NONE" -> livingEntity.stopUsingItem();
case "MAIN_HAND" -> livingEntity.startUsingItem(InteractionHand.MAIN_HAND, true);
case "OFF_HAND" -> livingEntity.startUsingItem(InteractionHand.OFF_HAND, true);
}
}
}

View File

@@ -0,0 +1,101 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancylib.ReflectionUtils;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.animal.Panda;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PandaAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"gene",
Arrays.stream(Panda.Gene.values())
.map(Enum::name)
.toList(),
List.of(EntityType.PANDA),
PandaAttributes::setGene
));
attributes.add(new NpcAttribute(
"eating",
List.of("true", "false"),
List.of(EntityType.PANDA),
PandaAttributes::setEating
));
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sitting", "onBack", "rolling"),
List.of(EntityType.PANDA),
PandaAttributes::setPose
));
return attributes;
}
private static void setGene(Npc npc, String value) {
Panda panda = ReflectionHelper.getEntity(npc);
Panda.Gene gene = Panda.Gene.valueOf(value.toUpperCase());
panda.setMainGene(gene);
}
private static void setPose(Npc npc, String value) {
Panda panda = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> {
setFlag(panda, 8, false); //sitting
panda.roll(false);
panda.setOnBack(false);
}
case "sitting" -> {
panda.roll(false);
panda.setOnBack(false);
setFlag(panda, 8, true); //sitting
}
case "onback" -> {
setFlag(panda, 8, false); //sitting
panda.roll(false);
panda.setOnBack(true);
}
case "rolling" -> {
setFlag(panda, 8, false); //sitting
panda.setOnBack(false);
panda.roll(true);
}
}
}
private static void setEating(Npc npc, String value) {
Panda panda = ReflectionHelper.getEntity(npc);
boolean eating = Boolean.parseBoolean(value);
panda.eat(eating);
}
private static void setFlag(Panda panda, int mask, boolean value) {
EntityDataAccessor<Byte> DATA_ID_FLAGS = (EntityDataAccessor<Byte>) ReflectionUtils.getValue(panda, "DATA_ID_FLAGS");
byte b0 = panda.getEntityData().get(DATA_ID_FLAGS);
if (value) {
panda.getEntityData().set(DATA_ID_FLAGS, (byte) (b0 | mask));
} else {
panda.getEntityData().set(DATA_ID_FLAGS, (byte) (b0 & ~mask));
}
}
}

View File

@@ -0,0 +1,59 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.Parrot;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ParrotAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
Arrays.stream(Parrot.Variant.values())
.map(Enum::name)
.toList(),
List.of(EntityType.PARROT),
ParrotAttributes::setVariant
));
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sitting"),
List.of(EntityType.PARROT),
ParrotAttributes::setPose
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
Parrot parrot = ReflectionHelper.getEntity(npc);
Parrot.Variant variant = Parrot.Variant.valueOf(value.toUpperCase());
parrot.setVariant(variant);
}
private static void setPose(Npc npc, String value) {
Parrot parrot = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> {
parrot.setOrderedToSit(false);
parrot.setInSittingPose(false, false);
}
case "sitting" -> {
parrot.setOrderedToSit(true);
parrot.setInSittingPose(true, false);
}
}
}
}

View File

@@ -0,0 +1,73 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.animal.Pig;
import net.minecraft.world.entity.animal.PigVariant;
import net.minecraft.world.item.Items;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class PigAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
getPigVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.PIG),
PigAttributes::setVariant
));
attributes.add(new NpcAttribute(
"has_saddle",
List.of("true", "false"),
List.of(EntityType.PIG),
PigAttributes::setHasSaddle
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
final Pig pig = ReflectionHelper.getEntity(npc);
Holder<PigVariant> variant = getPigVariantRegistry()
.get(ResourceKey.create(
Registries.PIG_VARIANT,
Identifier.withDefaultNamespace(value.toLowerCase())
))
.orElseThrow();
pig.setVariant(variant);
}
private static void setHasSaddle(Npc npc, String value) {
Pig pig = ReflectionHelper.getEntity(npc);
boolean hasSaddle = Boolean.parseBoolean(value.toLowerCase());
if (hasSaddle) {
pig.setItemSlot(EquipmentSlot.SADDLE, Items.SADDLE.getDefaultInstance());
}
}
private static HolderLookup.RegistryLookup<PigVariant> getPigVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.PIG_VARIANT);
}
}

View File

@@ -0,0 +1,34 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.monster.piglin.Piglin;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class PiglinAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"dancing",
List.of("true", "false"),
List.of(EntityType.PIGLIN),
PiglinAttributes::setDancing
));
return attributes;
}
private static void setDancing(Npc npc, String value) {
Piglin piglin = ReflectionHelper.getEntity(npc);
boolean dancing = Boolean.parseBoolean(value);
piglin.setDancing(dancing);
}
}

View File

@@ -0,0 +1,40 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancylib.ReflectionUtils;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class PlayerAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "crouching", "sleeping", "swimming", "sitting"),
List.of(EntityType.PLAYER),
PlayerAttributes::setPose
));
return attributes;
}
private static void setPose(Npc npc, String value) {
Player player = ReflectionHelper.getEntity(npc);
Pose pose = Pose.valueOf(value.toUpperCase());
EntityDataAccessor<Pose> DATA_POSE = (EntityDataAccessor<Pose>) ReflectionUtils.getStaticValue(Entity.class, "DATA_POSE"); // DATA_POSE
player.getEntityData().set(DATA_POSE, pose);
}
}

View File

@@ -0,0 +1,37 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.Rabbit;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class RabbitAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"variant",
Arrays.stream(Rabbit.Variant.values())
.map(Enum::name)
.toList(),
List.of(EntityType.RABBIT),
RabbitAttributes::setVariant
));
return attributes;
}
private static void setVariant(Npc npc, String value) {
Rabbit rabbit = ReflectionHelper.getEntity(npc);
Rabbit.Variant variant = Rabbit.Variant.valueOf(value.toUpperCase());
rabbit.setVariant(variant);
}
}

View File

@@ -0,0 +1,50 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.sheep.Sheep;
import net.minecraft.world.item.DyeColor;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SheepAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"wool_color",
Arrays.stream(DyeColor.values()).map(dyeColor -> dyeColor.name().toLowerCase()).toList(),
List.of(EntityType.SHEEP),
SheepAttributes::setColor
));
attributes.add(new NpcAttribute(
"sheared",
Arrays.asList("true", "false"),
List.of(EntityType.SHEEP),
SheepAttributes::setSheared
));
return attributes;
}
private static void setColor(Npc npc, String value) {
Sheep sheep = ReflectionHelper.getEntity(npc);
sheep.setColor(DyeColor.byName(value.toLowerCase(), DyeColor.WHITE));
}
private static void setSheared(Npc npc, String value) {
Sheep sheep = ReflectionHelper.getEntity(npc);
boolean sheared = Boolean.parseBoolean(value);
sheep.setSheared(sheared);
}
}

View File

@@ -0,0 +1,54 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.monster.Shulker;
import net.minecraft.world.item.DyeColor;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ShulkerAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"color",
Arrays.stream(DyeColor.values())
.map(Enum::name)
.toList(),
List.of(EntityType.SHULKER),
ShulkerAttributes::setColor
));
attributes.add(new NpcAttribute(
"shield",
List.of("open", "closed"),
List.of(EntityType.SHULKER),
ShulkerAttributes::setShield
));
return attributes;
}
private static void setColor(Npc npc, String value) {
Shulker shulker = ReflectionHelper.getEntity(npc);
DyeColor color = DyeColor.byName(value.toLowerCase(), DyeColor.PURPLE);
shulker.getEntityData().set(Shulker.DATA_COLOR_ID, (byte) color.getId());
}
private static void setShield(Npc npc, String value) {
Shulker shulker = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "closed" -> shulker.setRawPeekAmount(0);
case "open" -> shulker.setRawPeekAmount(Byte.MAX_VALUE);
}
}
}

View File

@@ -0,0 +1,40 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.monster.Slime;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class SlimeAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"size",
new ArrayList<>(),
List.of(EntityType.SLIME),
SlimeAttributes::setSize
));
return attributes;
}
private static void setSize(Npc npc, String value) {
Slime slime = ReflectionHelper.getEntity(npc);
int size;
try {
size = Integer.parseInt(value);
} catch (NumberFormatException e) {
return;
}
slime.setSize(size, false);
}
}

View File

@@ -0,0 +1,36 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.sniffer.Sniffer;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SnifferAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"state",
Arrays.stream(Sniffer.State.values())
.map(Enum::name)
.toList(),
List.of(EntityType.SNIFFER),
SnifferAttributes::setState
));
return attributes;
}
private static void setState(Npc npc, String value) {
final Sniffer sniffer = ReflectionHelper.getEntity(npc);
Sniffer.State state = Sniffer.State.valueOf(value.toUpperCase());
sniffer.transitionTo(state);
}
}

View File

@@ -0,0 +1,39 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.monster.SpellcasterIllager;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Spellcaster;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SpellCasterAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"casting",
Arrays.stream(SpellcasterIllager.IllagerSpell.values()).map(Enum::toString).toList(),
Arrays.stream(EntityType.values())
.filter(type -> type.getEntityClass() != null && Spellcaster.class.isAssignableFrom(type.getEntityClass()))
.toList(),
SpellCasterAttributes::setPose
));
return attributes;
}
private static void setPose(Npc npc, String value) {
SpellcasterIllager spellcasterIllager = ReflectionHelper.getEntity(npc);
SpellcasterIllager.IllagerSpell spell = SpellcasterIllager.IllagerSpell.valueOf(value);
spellcasterIllager.setIsCastingSpell(spell);
}
}

View File

@@ -0,0 +1,36 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minecraft.world.entity.Display;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class TextDisplayAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"text",
new ArrayList<>(),
List.of(EntityType.TEXT_DISPLAY),
TextDisplayAttributes::setText
));
return attributes;
}
private static void setText(Npc npc, String value) {
Display.TextDisplay display = ReflectionHelper.getEntity(npc);
Component text = MiniMessage.miniMessage().deserialize(value);
display.setText(PaperAdventure.asVanilla(text));
}
}

View File

@@ -0,0 +1,72 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.animal.TropicalFish;
import net.minecraft.world.item.DyeColor;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TropicalFishAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"pattern",
Arrays.stream(TropicalFish.Pattern.values())
.map(Enum::name)
.toList(),
List.of(EntityType.TROPICAL_FISH),
TropicalFishAttributes::setPattern
));
attributes.add(new NpcAttribute(
"base_color",
Arrays.stream(DyeColor.values())
.map(Enum::name)
.toList(),
List.of(EntityType.TROPICAL_FISH),
TropicalFishAttributes::setBaseColor
));
attributes.add(new NpcAttribute(
"pattern_color",
Arrays.stream(DyeColor.values())
.map(Enum::name)
.toList(),
List.of(EntityType.TROPICAL_FISH),
TropicalFishAttributes::setPatternColor
));
return attributes;
}
private static void setPattern(Npc npc, String value) {
TropicalFish tropicalFish = ReflectionHelper.getEntity(npc);
TropicalFish.Pattern pattern = TropicalFish.Pattern.valueOf(value.toUpperCase());
tropicalFish.setPackedVariant(pattern.getPackedId());
}
private static void setBaseColor(Npc npc, String value) {
TropicalFish tropicalFish = ReflectionHelper.getEntity(npc);
DyeColor color = DyeColor.byName(value.toLowerCase(), DyeColor.WHITE);
TropicalFish.Variant variant = new TropicalFish.Variant(tropicalFish.getPattern(), color, tropicalFish.getPatternColor());
tropicalFish.setPackedVariant(variant.getPackedId());
}
private static void setPatternColor(Npc npc, String value) {
TropicalFish tropicalFish = ReflectionHelper.getEntity(npc);
DyeColor color = DyeColor.byName(value.toLowerCase(), DyeColor.WHITE);
TropicalFish.Variant variant = new TropicalFish.Variant(tropicalFish.getPattern(), tropicalFish.getBaseColor(), color);
tropicalFish.setPackedVariant(variant.getPackedId());
}
}

View File

@@ -0,0 +1,36 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.world.entity.monster.Vex;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class VexAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"charging",
List.of("true", "false"),
List.of(EntityType.VEX),
VexAttributes::setCharging
));
return attributes;
}
private static void setCharging(Npc npc, String value) {
Vex vex = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "true" -> vex.setIsCharging(true);
case "false" -> vex.setIsCharging(false);
}
}
}

View File

@@ -0,0 +1,55 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerProfession;
import net.minecraft.world.entity.npc.VillagerType;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class VillagerAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"profession",
BuiltInRegistries.VILLAGER_PROFESSION.keySet().stream().map(Identifier::getPath).toList(),
List.of(EntityType.VILLAGER),
VillagerAttributes::setProfession
));
attributes.add(new NpcAttribute(
"type",
BuiltInRegistries.VILLAGER_TYPE.keySet().stream().map(Identifier::getPath).toList(),
List.of(EntityType.VILLAGER),
VillagerAttributes::setType
));
return attributes;
}
private static void setProfession(Npc npc, String value) {
Villager villager = ReflectionHelper.getEntity(npc);
Holder<VillagerProfession> profession = BuiltInRegistries.VILLAGER_PROFESSION.get(Identifier.tryParse(value)).orElseThrow();
villager.setVillagerData(villager.getVillagerData().withProfession(profession));
}
private static void setType(Npc npc, String value) {
Villager villager = ReflectionHelper.getEntity(npc);
Holder<VillagerType> type = BuiltInRegistries.VILLAGER_TYPE.get(Identifier.tryParse(value)).orElseThrow();
villager.setVillagerData(villager.getVillagerData().withType(type));
}
}

View File

@@ -0,0 +1,127 @@
package de.oliver.fancynpcs.v1_21_11.attributes;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.NpcAttribute;
import de.oliver.fancynpcs.v1_21_11.ReflectionHelper;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.animal.wolf.Wolf;
import net.minecraft.world.entity.animal.wolf.WolfVariant;
import net.minecraft.world.item.DyeColor;
import org.bukkit.entity.EntityType;
import java.util.ArrayList;
import java.util.List;
public class WolfAttributes {
public static List<NpcAttribute> getAllAttributes() {
List<NpcAttribute> attributes = new ArrayList<>();
attributes.add(new NpcAttribute(
"pose",
List.of("standing", "sitting"),
List.of(EntityType.WOLF),
WolfAttributes::setPose
));
attributes.add(new NpcAttribute(
"angry",
List.of("true", "false"),
List.of(EntityType.WOLF),
WolfAttributes::setAngry
));
attributes.add(new NpcAttribute(
"variant",
getWolfVariantRegistry()
.listElementIds()
.map(id -> id.identifier().getPath())
.toList(),
List.of(EntityType.WOLF),
WolfAttributes::setVariant
));
attributes.add(new NpcAttribute(
"collar_color",
List.of("RED", "BLUE", "YELLOW", "GREEN", "PURPLE", "ORANGE", "LIME", "MAGENTA", "BROWN", "WHITE", "GRAY", "LIGHT_GRAY", "LIGHT_BLUE", "BLACK", "CYAN", "PINK", "NONE"),
List.of(EntityType.WOLF),
WolfAttributes::setCollarColor
));
return attributes;
}
private static void setPose(Npc npc, String value) {
Wolf wolf = ReflectionHelper.getEntity(npc);
switch (value.toLowerCase()) {
case "standing" -> wolf.setInSittingPose(false, false);
case "sitting" -> wolf.setInSittingPose(true, false);
}
}
private static void setAngry(Npc npc, String value) {
Wolf wolf = ReflectionHelper.getEntity(npc);
boolean angry = Boolean.parseBoolean(value.toLowerCase());
wolf.setTimeToRemainAngry(angry ? 100 : 0);
}
private static void setVariant(Npc npc, String value) {
Wolf wolf = ReflectionHelper.getEntity(npc);
Registry<WolfVariant> registry = wolf.level().registryAccess().lookupOrThrow(Registries.WOLF_VARIANT);
Identifier variantLocation = Identifier.tryParse("minecraft:" + value.toLowerCase());
if (variantLocation == null) {
System.out.println("Invalid variant name: " + value);
return;
}
WolfVariant variant = registry.getOptional(variantLocation).orElse(null);
if (variant == null) {
System.out.println("Wolf variant not found: " + variantLocation);
return;
}
// Get the ResourceKey from the registry
registry.getResourceKey(variant).ifPresentOrElse(
key -> {
// Get the holder from the registry — this is properly bound
Holder<WolfVariant> holder = registry.wrapAsHolder(variant);
wolf.setVariant(holder);
},
() -> System.out.println("Wolf variant not registered: " + variantLocation)
);
}
private static void setCollarColor(Npc npc, String value) {
Wolf wolf = ReflectionHelper.getEntity(npc);
if (value.equalsIgnoreCase("none") || value.isEmpty()) {
// Reset to no collar
wolf.setTame(false, false);
return;
}
try {
DyeColor color = DyeColor.valueOf(value.toUpperCase());
if (!wolf.isTame()) {
wolf.setTame(true, false);
}
wolf.setCollarColor(color);
} catch (IllegalArgumentException e) {
System.out.println("Invalid wolf collar color: " + value);
}
}
private static HolderLookup.RegistryLookup<WolfVariant> getWolfVariantRegistry() {
return MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.WOLF_VARIANT);
}
}

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -12,7 +12,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -10,7 +10,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -11,7 +11,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -11,7 +11,7 @@ dependencies {
compileOnly(project(":plugins:fancynpcs:fn-api"))
compileOnly(project(":libraries:common"))
compileOnly("org.lushplugins:ChatColorHandler:6.0.2")
compileOnly("org.lushplugins:ChatColorHandler:6.0.0")
}

View File

@@ -387,11 +387,19 @@ public class Npc_1_21_9 extends Npc {
}
private ClientboundPlayerInfoUpdatePacket.Entry getEntry(ServerPlayer npcPlayer, ServerPlayer viewer) {
GameProfile profile = npcPlayer.getGameProfile();
if (data.isMirrorSkin()) {
GameProfile newProfile = new GameProfile(profile.id(), profile.name());
newProfile.properties().putAll(viewer.getGameProfile().properties());
profile = newProfile;
GameProfile profile;
if (!data.isMirrorSkin()) {
profile = npcPlayer.getGameProfile();
} else {
Property textures = viewer.getGameProfile().properties().get("textures").iterator().next();
PropertyMap propertyMap = new PropertyMap(
ImmutableMultimap.of(
"textures",
new Property("textures", textures.value(), textures.signature())
)
);
profile = new GameProfile(uuid, localName, propertyMap);
}
return new ClientboundPlayerInfoUpdatePacket.Entry(

View File

@@ -23,7 +23,8 @@
"1.21.7",
"1.21.8",
"1.21.9",
"1.21.10"
"1.21.10",
"1.21.11"
],
"channel": "RELEASE",
"loaders": [

Some files were not shown because too many files have changed in this diff Show More