Add FancyNpcs source
70
plugins/fancynpcs/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Required env: java 21, git
|
||||
Required plugins: discord notifier
|
||||
Required credentials: MODRINTH_PUBLISH_API_TOKEN, HANGAR_PUBLISH_API_TOKEN
|
||||
*/
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
GRADLE_OPTS = '-Dorg.gradle.daemon=false'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
git url: 'https://github.com/FancyMcPlugins/FancyNpcs', branch: 'main'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'chmod +x gradlew'
|
||||
sh './gradlew clean shadowJar'
|
||||
echo 'Built the plugin!'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
// Load the secrets and make them available as environment variables
|
||||
withCredentials([
|
||||
string(credentialsId: 'MODRINTH_PUBLISH_API_TOKEN', variable: 'MODRINTH_PUBLISH_API_TOKEN'),
|
||||
string(credentialsId: 'HANGAR_PUBLISH_API_TOKEN', variable: 'HANGAR_PUBLISH_API_TOKEN')
|
||||
]) {
|
||||
sh 'export MODRINTH_PUBLISH_API_TOKEN=${MODRINTH_PUBLISH_API_TOKEN} && ./gradlew modrinth'
|
||||
echo 'Published to Modrinth!'
|
||||
|
||||
sh 'export HANGAR_PUBLISH_API_TOKEN=${HANGAR_PUBLISH_API_TOKEN} && ./gradlew publishAllPublicationsToHangar'
|
||||
echo 'Published to Hangar!'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: '**/build/libs/FancyNpcs-*.jar', allowEmptyArchive: true
|
||||
}
|
||||
success {
|
||||
withCredentials([
|
||||
string(credentialsId: 'DISC_WEBHOOK_URL', variable: 'DISC_WEBHOOK_URL')
|
||||
]) {
|
||||
discordSend description: "**Build:** ${env.BUILD_NUMBER} \n**Status:** ${currentBuild.currentResult} \n**Download:** https://modrinth.com/plugin/fancynpcs/versions",
|
||||
footer: "Jenkins Pipeline", link: env.BUILD_URL, result: 'SUCCESS', title: "FancyNpcs #${env.BUILD_NUMBER}", webhookURL: "${DISC_WEBHOOK_URL}"
|
||||
}
|
||||
echo 'Build was successful!'
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
withCredentials([
|
||||
string(credentialsId: 'DISC_WEBHOOK_URL', variable: 'DISC_WEBHOOK_URL')
|
||||
]) {
|
||||
discordSend description: "**Build:** ${env.BUILD_NUMBER} \n**Status:** ${currentBuild.currentResult}", footer: "Jenkins Pipeline", link: env.BUILD_URL, result: 'FAILURE', title: "FancyNpcs #${env.BUILD_NUMBER}", "${DISC_WEBHOOK_URL}"
|
||||
}
|
||||
}
|
||||
echo 'Build failed!'
|
||||
}
|
||||
}
|
||||
}
|
||||
146
plugins/fancynpcs/README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
[](https://github.com/FancyMcPlugins/FancyNpcs/releases/latest)
|
||||
[](https://papermc.io/software/folia)
|
||||
[](https://discord.gg/ZUgYCEJUEx)
|
||||
[](https://github.com/FancyMcPlugins/FancyNpcs/releases/latest)
|
||||
[](https://modrinth.com/plugin/fancynpcs)
|
||||
[](https://www.codefactor.io/repository/github/fancymcplugins/fancynpcs/issues/main)
|
||||
|
||||
[](https://modrinth.com/plugin/fancynpcs)
|
||||
[](https://hangar.papermc.io/Oliver/FancyNpcs)
|
||||
|
||||
<br />
|
||||
|
||||
Simple, lightweight and feature-rich NPC plugin for **[Paper](https://papermc.io/software/paper)** (and **[Folia](https://papermc.io/software/folia)**) servers using packets.
|
||||
|
||||
</div>
|
||||
|
||||
## Features
|
||||
|
||||
With this plugin you can create NPCs with customizable properties like:
|
||||
|
||||
- **Type** (Cow, Pig, Player, etc.)
|
||||
- **Skin** (from username, texture URL or placeholder)
|
||||
- **Glowing** (in all colors)
|
||||
- **Attributes** (pose, visibility, variant, etc.)
|
||||
- **Equipment** (eg. holding a diamond sword and wearing leather armor)
|
||||
- **Interactions** (execute commands, send messages etc.)
|
||||
- ...and much more!
|
||||
|
||||
Check out **[images section](#images)** down below.
|
||||
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
Paper **1.19.4** - **1.21.5** with **Java 21** (or higher) is required. Plugin should also work on **Paper** forks.
|
||||
|
||||
**Spigot** is **not** supported.
|
||||
|
||||
### Download (Stable)
|
||||
|
||||
- **[Hangar](https://hangar.papermc.io/Oliver/FancyNpcs)**
|
||||
- **[Modrinth](https://modrinth.com/plugin/fancynpcs)**
|
||||
- **[GitHub Releases](https://github.com/FancyMcPlugins/FancyNpcs/releases)**
|
||||
|
||||
### Download (Development Builds)
|
||||
|
||||
- **[Jenkins CI](https://jenkins.fancyplugins.de/job/FancyNpcs/)**
|
||||
- **[FancyPlugins Website](https://fancyplugins.de/FancyNpcs/download)**
|
||||
|
||||
<br />
|
||||
|
||||
## Documentation
|
||||
|
||||
Official documentation is hosted **[here](https://fancyplugins.de/docs/fancynpcs.html)**. Quick reference:
|
||||
|
||||
- **[Getting Started](https://fancyplugins.de/docs/fn-getting-started.html)**
|
||||
- **[Command Reference](https://fancyplugins.de/docs/fn-commands.html)**
|
||||
- **[Using API](https://fancyplugins.de/docs/fn-api.html)**
|
||||
|
||||
**Have more questions?** Feel free to ask them on our **[Discord](https://discord.gg/ZUgYCEJUEx)** server.
|
||||
|
||||
<br />
|
||||
|
||||
## Developer API
|
||||
|
||||
More information can be found in **[Documentation](https://fancyplugins.de/docs/fn-api.html)** and **[Javadocs](https://repo.fancyplugins.de/javadoc/releases/de/oliver/FancyNpcs/latest)**.
|
||||
|
||||
### Maven
|
||||
|
||||
```xml
|
||||
|
||||
<repository>
|
||||
<id>fancyplugins-releases</id>
|
||||
<name>FancyPlugins Repository</name>
|
||||
<url>https://repo.fancyplugins.de/releases</url>
|
||||
</repository>
|
||||
```
|
||||
|
||||
```xml
|
||||
|
||||
<dependency>
|
||||
<groupId>de.oliver</groupId>
|
||||
<artifactId>FancyNpcs</artifactId>
|
||||
<version>[VERSION]</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
|
||||
```groovy
|
||||
repositories {
|
||||
maven("https://repo.fancyplugins.de/releases")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("de.oliver:FancyNpcs:[VERSION]")
|
||||
}
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
## Building
|
||||
|
||||
Follow these steps to build the plugin locally:
|
||||
|
||||
```shell
|
||||
# Cloning repository.
|
||||
$ git clone https://github.com/FancyMcPlugins/FancyNpcs.git
|
||||
# Entering cloned repository.
|
||||
$ cd FancyNpcs
|
||||
# Compiling and building artifacts.
|
||||
$ gradlew shadowJar
|
||||
# Once successfully built, plugin .jar can be found in /build/libs directory.
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
## Images
|
||||
|
||||
Images showcasing the plugin, sent to us by our community.
|
||||
|
||||

|
||||
<sup>Provided by [Explorer's Eden](https://explorerseden.eu/)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [Explorer's Eden](https://explorerseden.eu/)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [Explorer's Eden](https://explorerseden.eu/)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [Beacon's Quest](https://www.beaconsquest.net/)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [@OliverSchlueter](https://github.com/OliverSchlueter)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [@OliverSchlueter](https://github.com/OliverSchlueter)</sup>
|
||||
|
||||

|
||||
<sup>Provided by [@Grabsky](https://github.com/Grabsky)</sup>
|
||||
71
plugins/fancynpcs/api/build.gradle.kts
Normal file
@@ -0,0 +1,71 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.19.4"
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:$minecraftVersion-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly("de.oliver:FancyLib:37")
|
||||
compileOnly("de.oliver.FancyAnalytics:logger:0.0.6")
|
||||
|
||||
implementation("org.lushplugins:ChatColorHandler:5.1.3")
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
archiveClassifier.set("")
|
||||
|
||||
relocate("org.lushplugins.chatcolorhandler", "de.oliver.fancynpcs.libs.chatcolorhandler")
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "fancypluginsReleases"
|
||||
url = uri("https://repo.fancyplugins.de/releases")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "fancypluginsSnapshots"
|
||||
url = uri("https://repo.fancyplugins.de/snapshots")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = rootProject.group.toString()
|
||||
artifactId = rootProject.name
|
||||
version = rootProject.version.toString()
|
||||
from(project.components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 17
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AttributeManager {
|
||||
|
||||
NpcAttribute getAttributeByName(EntityType type, String name);
|
||||
|
||||
List<NpcAttribute> getAllAttributes();
|
||||
|
||||
List<NpcAttribute> getAllAttributesForEntityType(EntityType type);
|
||||
|
||||
void registerAttribute(NpcAttribute attribute);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface FancyNpcsConfig {
|
||||
|
||||
boolean isSkipInvisibleNpcs();
|
||||
|
||||
boolean isInteractionCooldownMessageDisabled();
|
||||
|
||||
boolean isMuteVersionNotification();
|
||||
|
||||
boolean isEnableAutoSave();
|
||||
|
||||
int getAutoSaveInterval();
|
||||
|
||||
int getNpcUpdateInterval();
|
||||
|
||||
int getNpcUpdateVisibilityInterval();
|
||||
|
||||
int getTurnToPlayerDistance();
|
||||
|
||||
boolean isTurnToPlayerResetToInitialDirection();
|
||||
|
||||
int getVisibilityDistance();
|
||||
|
||||
int getRemoveNpcsFromPlayerlistDelay();
|
||||
|
||||
String getMineSkinApiKey();
|
||||
|
||||
List<String> getBlockedCommands();
|
||||
|
||||
Map<String, Integer> getMaxNpcsPerPermission();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import de.oliver.fancyanalytics.logger.ExtendedFancyLogger;
|
||||
import de.oliver.fancylib.serverSoftware.schedulers.FancyScheduler;
|
||||
import de.oliver.fancylib.translations.Translator;
|
||||
import de.oliver.fancynpcs.api.actions.ActionManager;
|
||||
import de.oliver.fancynpcs.api.skins.SkinManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface FancyNpcsPlugin {
|
||||
|
||||
static FancyNpcsPlugin get() {
|
||||
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
|
||||
if (pluginManager.isPluginEnabled("FancyNpcs")) {
|
||||
return (FancyNpcsPlugin) pluginManager.getPlugin("FancyNpcs");
|
||||
}
|
||||
|
||||
throw new NullPointerException("Plugin is not enabled");
|
||||
}
|
||||
|
||||
JavaPlugin getPlugin();
|
||||
|
||||
ExtendedFancyLogger getFancyLogger();
|
||||
|
||||
ScheduledExecutorService getNpcThread();
|
||||
|
||||
/**
|
||||
* Creates a new thread with the given name and runnable.
|
||||
* Warning: Do not use this method, it is for internal use only.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
Thread newThread(String name, Runnable runnable);
|
||||
|
||||
FancyScheduler getScheduler();
|
||||
|
||||
Function<NpcData, Npc> getNpcAdapter();
|
||||
|
||||
FancyNpcsConfig getFancyNpcConfig();
|
||||
|
||||
NpcManager getNpcManager();
|
||||
|
||||
AttributeManager getAttributeManager();
|
||||
|
||||
ActionManager getActionManager();
|
||||
|
||||
SkinManager getSkinManager();
|
||||
|
||||
Translator getTranslator();
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import de.oliver.fancylib.RandomUtils;
|
||||
import de.oliver.fancylib.translations.Translator;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutor;
|
||||
import de.oliver.fancynpcs.api.events.NpcInteractEvent;
|
||||
import de.oliver.fancynpcs.api.utils.Interval;
|
||||
import de.oliver.fancynpcs.api.utils.Interval.Unit;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public abstract class Npc {
|
||||
|
||||
private static final NpcAttribute INVISIBLE_ATTRIBUTE = FancyNpcsPlugin.get().getAttributeManager().getAttributeByName(EntityType.PLAYER, "invisible");
|
||||
private static final char[] localNameChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'k', 'l', 'm', 'n', 'o', 'r'};
|
||||
protected final Map<UUID, Boolean> isTeamCreated = new ConcurrentHashMap<>();
|
||||
protected final Map<UUID, Boolean> isVisibleForPlayer = new ConcurrentHashMap<>();
|
||||
protected final Map<UUID, Boolean> isLookingAtPlayer = new ConcurrentHashMap<>();
|
||||
protected final Map<UUID, Long> lastPlayerInteraction = new ConcurrentHashMap<>();
|
||||
private final Translator translator = FancyNpcsPlugin.get().getTranslator();
|
||||
protected NpcData data;
|
||||
protected boolean saveToFile;
|
||||
|
||||
public Npc(NpcData data) {
|
||||
this.data = data;
|
||||
this.saveToFile = true;
|
||||
}
|
||||
|
||||
protected String generateLocalName() {
|
||||
String localName = "";
|
||||
for (int i = 0; i < 8; i++) {
|
||||
localName += "&" + localNameChars[(int) RandomUtils.randomInRange(0, localNameChars.length)];
|
||||
}
|
||||
|
||||
localName = ChatColor.translateAlternateColorCodes('&', localName);
|
||||
|
||||
return localName;
|
||||
}
|
||||
|
||||
public abstract void create();
|
||||
|
||||
public abstract void spawn(Player player);
|
||||
|
||||
public void spawnForAll() {
|
||||
FancyNpcsPlugin.get().getNpcThread().submit(() -> {
|
||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||
spawn(onlinePlayer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract void remove(Player player);
|
||||
|
||||
public void removeForAll() {
|
||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||
remove(onlinePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the NPC should be visible for the player.
|
||||
*
|
||||
* @param player The player to check for.
|
||||
* @return True if the NPC should be visible for the player, otherwise false.
|
||||
*/
|
||||
protected boolean shouldBeVisible(Player player) {
|
||||
int visibilityDistance = (data.getVisibilityDistance() > -1) ? data.getVisibilityDistance() : FancyNpcsPlugin.get().getFancyNpcConfig().getVisibilityDistance();
|
||||
|
||||
if (visibilityDistance == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.isSpawnEntity()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.getLocation() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.getLocation().getWorld() != data.getLocation().getWorld()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (visibilityDistance != Integer.MAX_VALUE && data.getLocation().distanceSquared(player.getLocation()) > visibilityDistance * visibilityDistance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FancyNpcsPlugin.get().getFancyNpcConfig().isSkipInvisibleNpcs() && data.getAttributes().getOrDefault(INVISIBLE_ATTRIBUTE, "false").equalsIgnoreCase("true") && !data.isGlowing() && data.getEquipment().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void checkAndUpdateVisibility(Player player) {
|
||||
FancyNpcsPlugin.get().getNpcThread().submit(() -> {
|
||||
boolean shouldBeVisible = shouldBeVisible(player);
|
||||
boolean wasVisible = isVisibleForPlayer.getOrDefault(player.getUniqueId(), false);
|
||||
|
||||
if (shouldBeVisible && !wasVisible) {
|
||||
spawn(player);
|
||||
} else if (!shouldBeVisible && wasVisible) {
|
||||
remove(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract void lookAt(Player player, Location location);
|
||||
|
||||
public abstract void update(Player player);
|
||||
|
||||
public void updateForAll() {
|
||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||
update(onlinePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void move(Player player, boolean swingArm);
|
||||
|
||||
public void move(Player player) {
|
||||
move(player, true);
|
||||
}
|
||||
|
||||
public void moveForAll(boolean swingArm) {
|
||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||
move(onlinePlayer, swingArm);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveForAll() {
|
||||
moveForAll(true);
|
||||
}
|
||||
|
||||
public void interact(Player player) {
|
||||
interact(player, ActionTrigger.CUSTOM);
|
||||
}
|
||||
|
||||
public void interact(Player player, ActionTrigger actionTrigger) {
|
||||
if (data.getInteractionCooldown() > 0) {
|
||||
final long interactionCooldownMillis = (long) (data.getInteractionCooldown() * 1000);
|
||||
final long lastInteractionMillis = lastPlayerInteraction.getOrDefault(player.getUniqueId(), 0L);
|
||||
final Interval interactionCooldownLeft = Interval.between(lastInteractionMillis + interactionCooldownMillis, System.currentTimeMillis(), Unit.MILLISECONDS);
|
||||
if (interactionCooldownLeft.as(Unit.MILLISECONDS) > 0) {
|
||||
|
||||
if (!FancyNpcsPlugin.get().getFancyNpcConfig().isInteractionCooldownMessageDisabled()) {
|
||||
translator.translate("interaction_on_cooldown").replace("time", interactionCooldownLeft.toString()).send(player);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
lastPlayerInteraction.put(player.getUniqueId(), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
List<NpcAction.NpcActionData> actions = data.getActions(actionTrigger);
|
||||
NpcInteractEvent npcInteractEvent = new NpcInteractEvent(this, data.getOnClick(), actions, player, actionTrigger);
|
||||
npcInteractEvent.callEvent();
|
||||
|
||||
if (npcInteractEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// onClick
|
||||
if (data.getOnClick() != null) {
|
||||
data.getOnClick().accept(player);
|
||||
}
|
||||
|
||||
// actions
|
||||
ActionExecutor.execute(actionTrigger, this, player);
|
||||
|
||||
if (actionTrigger == ActionTrigger.LEFT_CLICK || actionTrigger == ActionTrigger.RIGHT_CLICK) {
|
||||
ActionExecutor.execute(ActionTrigger.ANY_CLICK, this, player);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void refreshEntityData(Player serverPlayer);
|
||||
|
||||
public abstract int getEntityId();
|
||||
|
||||
public NpcData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public abstract float getEyeHeight();
|
||||
|
||||
public Map<UUID, Boolean> getIsTeamCreated() {
|
||||
return isTeamCreated;
|
||||
}
|
||||
|
||||
public Map<UUID, Boolean> getIsVisibleForPlayer() {
|
||||
return isVisibleForPlayer;
|
||||
}
|
||||
|
||||
public Map<UUID, Boolean> getIsLookingAtPlayer() {
|
||||
return isLookingAtPlayer;
|
||||
}
|
||||
|
||||
public Map<UUID, Long> getLastPlayerInteraction() {
|
||||
return lastPlayerInteraction;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return data.isDirty();
|
||||
}
|
||||
|
||||
public void setDirty(boolean dirty) {
|
||||
data.setDirty(dirty);
|
||||
}
|
||||
|
||||
public boolean isSaveToFile() {
|
||||
return saveToFile;
|
||||
}
|
||||
|
||||
public void setSaveToFile(boolean saveToFile) {
|
||||
this.saveToFile = saveToFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class NpcAttribute {
|
||||
|
||||
private final String name;
|
||||
private final List<String> possibleValues;
|
||||
private final List<EntityType> types;
|
||||
private final BiConsumer<Npc, String> applyFunc; // npc, value
|
||||
|
||||
public NpcAttribute(String name, List<String> possibleValues, List<EntityType> types, BiConsumer<Npc, String> applyFunc) {
|
||||
this.name = name;
|
||||
this.possibleValues = possibleValues;
|
||||
this.types = types;
|
||||
this.applyFunc = applyFunc;
|
||||
}
|
||||
|
||||
public boolean isValidValue(String value) {
|
||||
if (possibleValues.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String pv : possibleValues) {
|
||||
if (pv.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void apply(Npc npc, String value) {
|
||||
applyFunc.accept(npc, value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getPossibleValues() {
|
||||
return possibleValues;
|
||||
}
|
||||
|
||||
public List<EntityType> getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.skins.SkinData;
|
||||
import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class NpcData {
|
||||
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final UUID creator;
|
||||
private String displayName;
|
||||
private SkinData skin;
|
||||
private boolean mirrorSkin;
|
||||
private Location location;
|
||||
private boolean showInTab;
|
||||
private boolean spawnEntity;
|
||||
private boolean collidable;
|
||||
private boolean glowing;
|
||||
private NamedTextColor glowingColor;
|
||||
private EntityType type;
|
||||
private Map<NpcEquipmentSlot, ItemStack> equipment;
|
||||
private Consumer<Player> onClick;
|
||||
private Map<ActionTrigger, List<NpcAction.NpcActionData>> actions;
|
||||
private boolean turnToPlayer;
|
||||
private float interactionCooldown;
|
||||
private float scale;
|
||||
private int visibilityDistance;
|
||||
private Map<NpcAttribute, String> attributes;
|
||||
private boolean isDirty;
|
||||
|
||||
public NpcData(
|
||||
String id,
|
||||
String name,
|
||||
UUID creator,
|
||||
String displayName,
|
||||
SkinData skin,
|
||||
Location location,
|
||||
boolean showInTab,
|
||||
boolean spawnEntity,
|
||||
boolean collidable,
|
||||
boolean glowing,
|
||||
NamedTextColor glowingColor,
|
||||
EntityType type,
|
||||
Map<NpcEquipmentSlot, ItemStack> equipment,
|
||||
boolean turnToPlayer,
|
||||
Consumer<Player> onClick,
|
||||
Map<ActionTrigger, List<NpcAction.NpcActionData>> actions,
|
||||
float interactionCooldown,
|
||||
float scale,
|
||||
int visibilityDistance,
|
||||
Map<NpcAttribute, String> attributes,
|
||||
boolean mirrorSkin
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.creator = creator;
|
||||
this.displayName = displayName;
|
||||
this.skin = skin;
|
||||
this.location = location;
|
||||
this.showInTab = showInTab;
|
||||
this.spawnEntity = spawnEntity;
|
||||
this.collidable = collidable;
|
||||
this.glowing = glowing;
|
||||
this.glowingColor = glowingColor;
|
||||
this.type = type;
|
||||
this.equipment = equipment;
|
||||
this.onClick = onClick;
|
||||
this.actions = actions;
|
||||
this.turnToPlayer = turnToPlayer;
|
||||
this.interactionCooldown = interactionCooldown;
|
||||
this.scale = scale;
|
||||
this.visibilityDistance = visibilityDistance;
|
||||
this.attributes = attributes;
|
||||
this.mirrorSkin = mirrorSkin;
|
||||
this.isDirty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default npc with random id
|
||||
*/
|
||||
public NpcData(String name, UUID creator, Location location) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.name = name;
|
||||
this.creator = creator;
|
||||
this.location = location;
|
||||
this.displayName = name;
|
||||
this.type = EntityType.PLAYER;
|
||||
this.showInTab = false;
|
||||
this.spawnEntity = true;
|
||||
this.collidable = true;
|
||||
this.glowing = false;
|
||||
this.glowingColor = NamedTextColor.WHITE;
|
||||
this.onClick = p -> {
|
||||
};
|
||||
this.actions = new ConcurrentHashMap<>();
|
||||
this.turnToPlayer = false;
|
||||
this.interactionCooldown = 0;
|
||||
this.scale = 1;
|
||||
this.visibilityDistance = -1;
|
||||
this.equipment = new ConcurrentHashMap<>();
|
||||
this.attributes = new ConcurrentHashMap<>();
|
||||
this.mirrorSkin = false;
|
||||
this.isDirty = true;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public UUID getCreator() {
|
||||
return creator == null ? UUID.fromString("00000000-0000-0000-0000-000000000000") : creator;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public NpcData setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SkinData getSkinData() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the skin data of the npc
|
||||
* Use this method, if you have a loaded skin data object (with texture and signature), otherwise use {@link #setSkin(String, SkinData.SkinVariant)}
|
||||
*
|
||||
* @param skinData the skin data
|
||||
*/
|
||||
public NpcData setSkinData(SkinData skinData) {
|
||||
this.skin = skinData;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the skin data and sets it as the skin of the npc
|
||||
*
|
||||
* @param skin a valid UUID, username, URL or file path
|
||||
* @param variant the skin variant
|
||||
*/
|
||||
public NpcData setSkin(String skin, SkinData.SkinVariant variant) {
|
||||
SkinData data = FancyNpcsPlugin.get().getSkinManager().getByIdentifier(skin, variant);
|
||||
return setSkinData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the skin data and sets it as the skin of the npc
|
||||
*
|
||||
* @param skin a valid UUID, username, URL or file path
|
||||
*/
|
||||
public NpcData setSkin(String skin) {
|
||||
return setSkin(skin, SkinData.SkinVariant.AUTO);
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public NpcData setLocation(Location location) {
|
||||
this.location = location;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isShowInTab() {
|
||||
return showInTab;
|
||||
}
|
||||
|
||||
public NpcData setShowInTab(boolean showInTab) {
|
||||
this.showInTab = showInTab;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSpawnEntity() {
|
||||
return spawnEntity;
|
||||
}
|
||||
|
||||
public NpcData setSpawnEntity(boolean spawnEntity) {
|
||||
this.spawnEntity = spawnEntity;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCollidable() {
|
||||
return collidable;
|
||||
}
|
||||
|
||||
public NpcData setCollidable(boolean collidable) {
|
||||
this.collidable = collidable;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isGlowing() {
|
||||
return glowing;
|
||||
}
|
||||
|
||||
public NpcData setGlowing(boolean glowing) {
|
||||
this.glowing = glowing;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NamedTextColor getGlowingColor() {
|
||||
return glowingColor;
|
||||
}
|
||||
|
||||
public NpcData setGlowingColor(NamedTextColor glowingColor) {
|
||||
this.glowingColor = glowingColor;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public NpcData setType(EntityType type) {
|
||||
this.type = type;
|
||||
attributes.clear();
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<NpcEquipmentSlot, ItemStack> getEquipment() {
|
||||
return equipment;
|
||||
}
|
||||
|
||||
public NpcData setEquipment(Map<NpcEquipmentSlot, ItemStack> equipment) {
|
||||
this.equipment = equipment;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NpcData addEquipment(NpcEquipmentSlot slot, ItemStack item) {
|
||||
equipment.put(slot, item);
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Consumer<Player> getOnClick() {
|
||||
return onClick;
|
||||
}
|
||||
|
||||
public NpcData setOnClick(Consumer<Player> onClick) {
|
||||
this.onClick = onClick;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<ActionTrigger, List<NpcAction.NpcActionData>> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public NpcData setActions(Map<ActionTrigger, List<NpcAction.NpcActionData>> actions) {
|
||||
this.actions = actions;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<NpcAction.NpcActionData> getActions(ActionTrigger trigger) {
|
||||
return actions.getOrDefault(trigger, new ArrayList<>());
|
||||
}
|
||||
|
||||
public NpcData setActions(ActionTrigger trigger, List<NpcAction.NpcActionData> actions) {
|
||||
this.actions.put(trigger, actions);
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NpcData addAction(ActionTrigger trigger, int order, NpcAction action, String value) {
|
||||
List<NpcAction.NpcActionData> a = actions.getOrDefault(trigger, new ArrayList<>());
|
||||
a.add(new NpcAction.NpcActionData(order, action, value));
|
||||
actions.put(trigger, a);
|
||||
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NpcData removeAction(ActionTrigger trigger, NpcAction action) {
|
||||
List<NpcAction.NpcActionData> a = actions.getOrDefault(trigger, new ArrayList<>());
|
||||
a.removeIf(ad -> ad.action().equals(action));
|
||||
actions.put(trigger, a);
|
||||
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isTurnToPlayer() {
|
||||
return turnToPlayer;
|
||||
}
|
||||
|
||||
public NpcData setTurnToPlayer(boolean turnToPlayer) {
|
||||
this.turnToPlayer = turnToPlayer;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getInteractionCooldown() {
|
||||
return interactionCooldown;
|
||||
}
|
||||
|
||||
public NpcData setInteractionCooldown(float interactionCooldown) {
|
||||
this.interactionCooldown = interactionCooldown;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public NpcData setScale(float scale) {
|
||||
this.scale = scale;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getVisibilityDistance() {
|
||||
return visibilityDistance;
|
||||
}
|
||||
|
||||
public NpcData setVisibilityDistance(int visibilityDistance) {
|
||||
this.visibilityDistance = visibilityDistance;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<NpcAttribute, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void addAttribute(NpcAttribute attribute, String value) {
|
||||
attributes.put(attribute, value);
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
public void applyAllAttributes(Npc npc) {
|
||||
for (NpcAttribute attribute : attributes.keySet()) {
|
||||
attribute.apply(npc, attributes.get(attribute));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMirrorSkin() {
|
||||
return mirrorSkin;
|
||||
}
|
||||
|
||||
public NpcData setMirrorSkin(boolean mirrorSkin) {
|
||||
this.mirrorSkin = mirrorSkin;
|
||||
isDirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
public void setDirty(boolean dirty) {
|
||||
isDirty = dirty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.oliver.fancynpcs.api;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface NpcManager {
|
||||
|
||||
void registerNpc(Npc npc);
|
||||
|
||||
void removeNpc(Npc npc);
|
||||
|
||||
@ApiStatus.Internal
|
||||
Npc getNpc(int entityId);
|
||||
|
||||
Npc getNpc(String name);
|
||||
|
||||
Npc getNpcById(String id);
|
||||
|
||||
Npc getNpc(String name, UUID creator);
|
||||
|
||||
Collection<Npc> getAllNpcs();
|
||||
|
||||
void saveNpcs(boolean force);
|
||||
|
||||
void loadNpcs();
|
||||
|
||||
void reloadNpcs();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package de.oliver.fancynpcs.api.actions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ActionManager {
|
||||
|
||||
void registerAction(NpcAction action);
|
||||
|
||||
NpcAction getActionByName(String name);
|
||||
|
||||
void unregisterAction(NpcAction action);
|
||||
|
||||
List<NpcAction> getAllActions();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancynpcs.api.actions;
|
||||
|
||||
public enum ActionTrigger {
|
||||
/**
|
||||
* represents any click interaction by a player.
|
||||
*/
|
||||
ANY_CLICK,
|
||||
/**
|
||||
* represents a left click interaction by a player.
|
||||
*/
|
||||
LEFT_CLICK,
|
||||
/**
|
||||
* represents a right click interaction by a player.
|
||||
*/
|
||||
RIGHT_CLICK,
|
||||
/**
|
||||
* represents interactions invoked by the API.
|
||||
*/
|
||||
CUSTOM,
|
||||
;
|
||||
|
||||
/**
|
||||
* Gets the ActionTrigger by its name.
|
||||
*
|
||||
* @param name the name of the ActionTrigger
|
||||
* @return the ActionTrigger or null if not found
|
||||
*/
|
||||
public static ActionTrigger getByName(final String name) {
|
||||
for (ActionTrigger trigger : values()) {
|
||||
if (trigger.name().equalsIgnoreCase(name)) {
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.oliver.fancynpcs.api.actions;
|
||||
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* The NpcAction class is an abstract class that represents an action that can be performed by an NPC.
|
||||
* Each NpcAction has a name and a flag indicating whether it requires a value.
|
||||
* <p>
|
||||
* The NpcAction class provides an abstract execute method that must be implemented by subclasses
|
||||
* to specify the behavior of the action when executed.
|
||||
* <p>
|
||||
* Subclasses of NpcAction can provide additional data using the NpcActionData record, which includes
|
||||
* an order value to specify the order of execution, the NpcAction itself, and a value associated with
|
||||
* the action.
|
||||
* <p>
|
||||
* This class provides getters for the name and the requiresValue flag of the action.
|
||||
*/
|
||||
public abstract class NpcAction {
|
||||
|
||||
private final String name;
|
||||
private final boolean requiresValue;
|
||||
|
||||
public NpcAction(String name, boolean requiresValue) {
|
||||
this.name = name;
|
||||
this.requiresValue = requiresValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the action associated with this NpcAction.
|
||||
*
|
||||
* @param context The context in which the action is being executed.
|
||||
* @param value The value associated with the action. Can be null if no value is required.
|
||||
*/
|
||||
public abstract void execute(@NotNull ActionExecutionContext context, @Nullable String value);
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean requiresValue() {
|
||||
return requiresValue;
|
||||
}
|
||||
|
||||
public record NpcActionData(int order, NpcAction action, String value) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package de.oliver.fancynpcs.api.actions.executor;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.types.BlockUntilDoneAction;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Context for executing a sequence of NPC actions initiated by different triggers.
|
||||
*/
|
||||
public class ActionExecutionContext {
|
||||
|
||||
/**
|
||||
* The trigger that initiated the action.
|
||||
* This is a final variable that represents the specific condition or
|
||||
* event that caused the action to be created in the context.
|
||||
*/
|
||||
private final ActionTrigger trigger;
|
||||
|
||||
/**
|
||||
* The NPC that the action is being executed on.
|
||||
*/
|
||||
private final Npc npc;
|
||||
|
||||
/**
|
||||
* The player involved in the action, may be null if no player is involved.
|
||||
*/
|
||||
private final @Nullable UUID player;
|
||||
|
||||
/**
|
||||
* A list of NpcActionData instances representing the sequence of actions
|
||||
* to be executed for the NPC in the given context.
|
||||
*/
|
||||
private final List<NpcAction.NpcActionData> actions;
|
||||
|
||||
/**
|
||||
* The index of the currently executing action in the list of actions.
|
||||
* <p>
|
||||
* This variable keeps track of which action within the action sequence
|
||||
* is currently being executed. It is incremented as actions are executed
|
||||
* sequentially using the {@link #runNext()} method.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default initial value is 0, indicating the start of the sequence.
|
||||
* When the index is set to -1, it signifies that the sequence has been
|
||||
* terminated and no further actions should be executed.
|
||||
* </p>
|
||||
*/
|
||||
private int actionIndex;
|
||||
|
||||
/**
|
||||
* Constructs an ActionExecutionContext with the specified ActionTrigger, Npc, and an optional Player.
|
||||
*
|
||||
* @param trigger the trigger that initiated the action
|
||||
* @param npc the NPC that the action is being executed on
|
||||
* @param player the player involved in the action, may be null if no player is involved
|
||||
*/
|
||||
public ActionExecutionContext(ActionTrigger trigger, Npc npc, @Nullable UUID player) {
|
||||
this.trigger = trigger;
|
||||
this.npc = npc;
|
||||
this.player = player;
|
||||
|
||||
this.actions = new ArrayList<>(npc.getData().getActions(trigger));
|
||||
this.actionIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an ActionExecutionContext with the specified ActionTrigger and Npc, without a Player.
|
||||
*
|
||||
* @param trigger the trigger that initiated the action
|
||||
* @param npc the NPC that the action is being executed on
|
||||
*/
|
||||
public ActionExecutionContext(ActionTrigger trigger, Npc npc) {
|
||||
this(trigger, npc, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the action at the specified index within the list of actions.
|
||||
*
|
||||
* @param index the index of the action to be executed. If the index is out of bounds, the method returns immediately.
|
||||
*/
|
||||
public void run(int index) {
|
||||
if (index < 0 || index >= actions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
NpcAction.NpcActionData actionData = actions.get(index);
|
||||
actionData.action().execute(this, actionData.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the next action in the list of actions.
|
||||
* <p>
|
||||
* If the current action index is out of bounds, the method returns immediately.
|
||||
* The action index is incremented after the action is executed.
|
||||
* </p>
|
||||
*/
|
||||
public void runNext() {
|
||||
if (actionIndex < 0 || actionIndex >= actions.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
run(actionIndex++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there are more actions to be executed.
|
||||
*
|
||||
* @return true if there are more actions to be executed, false otherwise
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return actionIndex >= 0 && actionIndex < actions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current action index to its initial state.
|
||||
* This is useful for re-running the sequence of actions from the beginning.
|
||||
*/
|
||||
public void reset() {
|
||||
actionIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the current action sequence by setting the action index to -1.
|
||||
* This effectively marks the context as finished and prevents any further actions from being executed.
|
||||
*/
|
||||
public void terminate() {
|
||||
actionIndex = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the action sequence has been terminated.
|
||||
*
|
||||
* @return true if the action index is -1, indicating the sequence is terminated; false otherwise
|
||||
*/
|
||||
public boolean isTerminated() {
|
||||
return actionIndex == -1;
|
||||
}
|
||||
|
||||
public boolean shouldBlockUntilDone() {
|
||||
for (NpcAction.NpcActionData action : actions) {
|
||||
if (action.action() instanceof BlockUntilDoneAction) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ActionTrigger getTrigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
public List<NpcAction.NpcActionData> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public @Nullable Player getPlayer() {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Bukkit.getPlayer(player);
|
||||
}
|
||||
|
||||
public int getActionIndex() {
|
||||
return actionIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.oliver.fancynpcs.api.actions.executor;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ActionExecutor {
|
||||
|
||||
private static final Map<String, ActionExecutionContext> runningContexts = new ConcurrentHashMap<>();
|
||||
|
||||
public static void execute(ActionTrigger trigger, Npc npc, Player player) {
|
||||
String key = getKey(trigger, npc, player);
|
||||
ActionExecutionContext runningContext = runningContexts.get(key);
|
||||
if (runningContext != null) {
|
||||
if (runningContext.shouldBlockUntilDone() && !runningContext.isTerminated()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ActionExecutionContext context = new ActionExecutionContext(trigger, npc, player.getUniqueId());
|
||||
runningContexts.put(key, context);
|
||||
|
||||
FancyNpcsPlugin.get().newThread("FancyNpcs-ActionExecutor", () -> {
|
||||
while (context.hasNext()) {
|
||||
context.runNext();
|
||||
}
|
||||
context.terminate();
|
||||
|
||||
runningContexts.remove(key);
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
private static String getKey(ActionTrigger trigger, Npc npc, Player player) {
|
||||
return trigger.name() + "_" + npc.getData().getId() + "_" + player.getUniqueId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
|
||||
/**
|
||||
* The BlockUntilDoneAction class is a specific implementation of the
|
||||
* NpcAction class that represents an action requiring the NPC (Non-Player
|
||||
* Character) to block its subsequent actions until the current interaction is
|
||||
* completed.
|
||||
* <p>
|
||||
*/
|
||||
public class BlockUntilDoneAction extends NpcAction {
|
||||
|
||||
public BlockUntilDoneAction() {
|
||||
super("block_until_done", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ActionExecutionContext context, String value) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lushplugins.chatcolorhandler.ChatColorHandler;
|
||||
import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
|
||||
|
||||
/**
|
||||
* Represents a console command action that can be executed for an NPC.
|
||||
*/
|
||||
public class ConsoleCommandAction extends NpcAction {
|
||||
|
||||
public ConsoleCommandAction() {
|
||||
super("console_command", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the console command action for an NPC.
|
||||
*
|
||||
* @param value The command string to be executed. The value can contain the placeholder "{player}" which will be replaced with the player's name.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = value;
|
||||
if (context.getPlayer() != null) {
|
||||
command = value.replace("{player}", context.getPlayer().getName());
|
||||
}
|
||||
|
||||
String finalCommand = ChatColorHandler.translate(command, context.getPlayer(), ParserTypes.placeholder());
|
||||
|
||||
FancyNpcsPlugin.get().getScheduler().runTask(null, () -> {
|
||||
try {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), finalCommand);
|
||||
} catch (Exception e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Failed to execute command: " + finalCommand);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* The ExecuteRandomActionAction class represents an action that can be executed randomly by an NPC.
|
||||
* <p>
|
||||
* The ExecuteRandomActionAction class provides an implementation for the execute method,
|
||||
* which executes a random action triggered by the given action trigger on the specified NPC and player.
|
||||
* The execution of the action is based on the actions associated with the NPC's data for the given trigger.
|
||||
*/
|
||||
public class ExecuteRandomActionAction extends NpcAction {
|
||||
|
||||
public ExecuteRandomActionAction() {
|
||||
super("execute_random_action", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a random action triggered by the given action trigger on the specified NPC and player.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
int currentIndex = context.getActionIndex();
|
||||
int actionCount = context.getActions().size();
|
||||
|
||||
int randomIndex = getRandomIndex(currentIndex, actionCount);
|
||||
|
||||
NpcActionData action = context.getActions().get(randomIndex);
|
||||
action.action().execute(context, action.value());
|
||||
|
||||
context.terminate();
|
||||
}
|
||||
|
||||
private int getRandomIndex(int from, int to) {
|
||||
return new Random().nextInt(to - from) + from;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.lushplugins.chatcolorhandler.ModernChatColorHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The MessageAction class represents an action that sends a message to the player when executed by an NPC.
|
||||
*/
|
||||
public class MessageAction extends NpcAction {
|
||||
|
||||
public MessageAction() {
|
||||
super("message", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the action associated with this NpcAction.
|
||||
*
|
||||
* @param value The value passed to the action.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.getPlayer().sendMessage(ModernChatColorHandler.translate(value, context.getPlayer()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
|
||||
public class NeedPermissionAction extends NpcAction {
|
||||
|
||||
public NeedPermissionAction() {
|
||||
super("need_permission", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.getPlayer().hasPermission(value)) {
|
||||
FancyNpcsPlugin.get().getTranslator().translate("action_missing_permissions").send(context.getPlayer());
|
||||
context.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lushplugins.chatcolorhandler.ChatColorHandler;
|
||||
import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
|
||||
|
||||
public class PlaySoundAction extends NpcAction {
|
||||
|
||||
public PlaySoundAction() {
|
||||
super("play_sound", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String sound = ChatColorHandler.translate(value, context.getPlayer(), ParserTypes.placeholder());
|
||||
|
||||
FancyNpcsPlugin.get().getScheduler().runTask(
|
||||
context.getPlayer().getLocation(),
|
||||
() -> {
|
||||
try {
|
||||
context.getPlayer().playSound(context.getPlayer().getLocation(), value, 1.0F, 1.0F);
|
||||
} catch (Exception e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Failed to play sound: " + sound);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lushplugins.chatcolorhandler.ChatColorHandler;
|
||||
import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
|
||||
|
||||
/**
|
||||
* Represents a player command action that can be executed when triggered by an NPC interaction.
|
||||
*/
|
||||
public class PlayerCommandAction extends NpcAction {
|
||||
|
||||
public PlayerCommandAction() {
|
||||
super("player_command", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a player command action when triggered by an NPC interaction.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = ChatColorHandler.translate(value, context.getPlayer(), ParserTypes.placeholder());
|
||||
|
||||
if (command.toLowerCase().startsWith("server")) {
|
||||
String[] args = value.split(" ");
|
||||
if (args.length < 2) {
|
||||
return;
|
||||
}
|
||||
String server = args[1];
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("Connect");
|
||||
out.writeUTF(server);
|
||||
context.getPlayer().sendPluginMessage(FancyNpcsPlugin.get().getPlugin(), "BungeeCord", out.toByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
FancyNpcsPlugin.get().getScheduler().runTask(
|
||||
context.getPlayer().getLocation(),
|
||||
() -> {
|
||||
try {
|
||||
context.getPlayer().chat("/" + command);
|
||||
} catch (Exception e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Failed to execute command: " + command);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lushplugins.chatcolorhandler.ChatColorHandler;
|
||||
import org.lushplugins.chatcolorhandler.parsers.ParserTypes;
|
||||
|
||||
/**
|
||||
* PlayerCommandAsOpAction is a npc action that allows a player to execute a command as an operator when triggered by an NPC interaction.
|
||||
*/
|
||||
public class PlayerCommandAsOpAction extends NpcAction {
|
||||
|
||||
public PlayerCommandAsOpAction() {
|
||||
super("player_command_as_op", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a player command as an operator when triggered by an NPC interaction.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = ChatColorHandler.translate(value, context.getPlayer(), ParserTypes.placeholder());
|
||||
|
||||
if (command.toLowerCase().startsWith("server")) {
|
||||
String[] args = value.split(" ");
|
||||
if (args.length < 2) {
|
||||
return;
|
||||
}
|
||||
String server = args[1];
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("Connect");
|
||||
out.writeUTF(server);
|
||||
context.getPlayer().sendPluginMessage(FancyNpcsPlugin.get().getPlugin(), "BungeeCord", out.toByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
FancyNpcsPlugin.get().getScheduler().runTask(
|
||||
context.getPlayer().getLocation(),
|
||||
() -> {
|
||||
boolean wasOp = context.getPlayer().isOp();
|
||||
|
||||
context.getPlayer().setOp(true);
|
||||
try {
|
||||
context.getPlayer().chat("/" + command);
|
||||
} catch (Exception e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Failed to execute command: " + command);
|
||||
} finally {
|
||||
context.getPlayer().setOp(wasOp);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The SendToServerAction class is a subclass of NpcAction that represents an action
|
||||
* to send data to the server using BungeeCord messaging.
|
||||
*/
|
||||
public class SendToServerAction extends NpcAction {
|
||||
|
||||
public SendToServerAction() {
|
||||
super("send_to_server", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the action associated with this NpcAction.
|
||||
*
|
||||
* @param value The value associated with the action.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF("Connect");
|
||||
out.writeUTF(value);
|
||||
context.getPlayer().sendPluginMessage(FancyNpcsPlugin.get().getPlugin(), "BungeeCord", out.toByteArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.oliver.fancynpcs.api.actions.types;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import de.oliver.fancynpcs.api.actions.executor.ActionExecutionContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class WaitAction extends NpcAction {
|
||||
|
||||
public WaitAction() {
|
||||
super("wait", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the "wait" action for an NPC.
|
||||
*
|
||||
* @param value The value representing the time to wait in seconds.
|
||||
*/
|
||||
@Override
|
||||
public void execute(@NotNull ActionExecutionContext context, String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int time;
|
||||
try {
|
||||
time = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Invalid time value for wait action: " + value);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(time * 1000L);
|
||||
} catch (InterruptedException e) {
|
||||
FancyNpcsPlugin.get().getFancyLogger().warn("Thread was interrupted while waiting");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when a new NPC is being created
|
||||
*/
|
||||
public class NpcCreateEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final CommandSender creator;
|
||||
private boolean isCancelled;
|
||||
|
||||
public NpcCreateEvent(@NotNull Npc npc, @NotNull CommandSender creator) {
|
||||
this.npc = npc;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the created npc
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player who created the npc
|
||||
*/
|
||||
public @NotNull CommandSender getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.isCancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.actions.NpcAction;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Is fired when a player interacts with a NPC
|
||||
*/
|
||||
public class NpcInteractEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@Nullable
|
||||
private final List<NpcAction.NpcActionData> actions;
|
||||
@NotNull
|
||||
private final Consumer<Player> onClick;
|
||||
@NotNull
|
||||
private final Player player;
|
||||
private final ActionTrigger actionTrigger;
|
||||
private boolean isCancelled;
|
||||
|
||||
public NpcInteractEvent(@NotNull Npc npc, @NotNull Consumer<Player> onClick, @NotNull List<NpcAction.NpcActionData> actions, @NotNull Player player, @NotNull ActionTrigger actionTrigger) {
|
||||
this.npc = npc;
|
||||
this.onClick = onClick;
|
||||
this.actions = actions;
|
||||
this.player = player;
|
||||
this.actionTrigger = actionTrigger;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modified npc
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the custom on click method that will run
|
||||
*/
|
||||
public @NotNull Consumer<Player> getOnClick() {
|
||||
return onClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the actions that will run
|
||||
*/
|
||||
public @Nullable List<NpcAction.NpcActionData> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns interaction type
|
||||
*/
|
||||
public @NotNull ActionTrigger getInteractionType() {
|
||||
return actionTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player who interacted with the npc
|
||||
*/
|
||||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.isCancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when a NPC is being modified
|
||||
*/
|
||||
public class NpcModifyEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final NpcModification modification;
|
||||
@NotNull
|
||||
private final Object newValue;
|
||||
@NotNull
|
||||
private final CommandSender modifier;
|
||||
private boolean isCancelled;
|
||||
|
||||
public NpcModifyEvent(@NotNull Npc npc, @NotNull NpcModification modification, Object newValue, @NotNull CommandSender modifier) {
|
||||
this.npc = npc;
|
||||
this.modification = modification;
|
||||
this.newValue = newValue;
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modified npc
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the modification that was being made
|
||||
*/
|
||||
public @NotNull NpcModification getModification() {
|
||||
return modification;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value that is being set
|
||||
*/
|
||||
public @NotNull Object getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sender who modified the npc
|
||||
*/
|
||||
public @NotNull CommandSender getModifier() {
|
||||
return modifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.isCancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
public enum NpcModification {
|
||||
ATTRIBUTE,
|
||||
COLLIDABLE,
|
||||
DISPLAY_NAME,
|
||||
EQUIPMENT,
|
||||
GLOWING,
|
||||
GLOWING_COLOR,
|
||||
INTERACTION_COOLDOWN,
|
||||
SCALE,
|
||||
VISIBILITY_DISTANCE,
|
||||
LOCATION,
|
||||
MIRROR_SKIN,
|
||||
PLAYER_COMMAND,
|
||||
SERVER_COMMAND,
|
||||
SHOW_IN_TAB,
|
||||
SKIN,
|
||||
TURN_TO_PLAYER,
|
||||
TYPE,
|
||||
// Messages.
|
||||
MESSAGE_ADD,
|
||||
MESSAGE_SET,
|
||||
MESSAGE_REMOVE,
|
||||
MESSAGE_CLEAR,
|
||||
MESSAGE_SEND_RANDOMLY,
|
||||
// Player commands.
|
||||
PLAYER_COMMAND_ADD,
|
||||
PLAYER_COMMAND_SET,
|
||||
PLAYER_COMMAND_REMOVE,
|
||||
PLAYER_COMMAND_CLEAR,
|
||||
PLAYER_COMMAND_SEND_RANDOMLY,
|
||||
// Server commands.
|
||||
SERVER_COMMAND_ADD,
|
||||
SERVER_COMMAND_SET,
|
||||
SERVER_COMMAND_REMOVE,
|
||||
SERVER_COMMAND_CLEAR,
|
||||
SERVER_COMMAND_SEND_RANDOMLY
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when a NPC is being deleted
|
||||
*/
|
||||
public class NpcRemoveEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final CommandSender receiver;
|
||||
private boolean isCancelled;
|
||||
|
||||
public NpcRemoveEvent(@NotNull Npc npc, @NotNull CommandSender receiver) {
|
||||
this.npc = npc;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the npc that is being removed
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player who removed the npc
|
||||
*/
|
||||
public @NotNull CommandSender getSender() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.isCancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when a NPC is being spawned
|
||||
*/
|
||||
public class NpcSpawnEvent extends Event implements Cancellable {
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final Player player;
|
||||
private boolean isCancelled;
|
||||
|
||||
public NpcSpawnEvent(@NotNull Npc npc, @NotNull Player player) {
|
||||
super(true);
|
||||
this.npc = npc;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the npc that is being spawned
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player to whom the spawn packets are being sent
|
||||
*/
|
||||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.isCancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when NPC starts looking at a player.
|
||||
*/
|
||||
public class NpcStartLookingEvent extends Event {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final Player player;
|
||||
|
||||
public NpcStartLookingEvent(@NotNull Npc npc, @NotNull Player player) {
|
||||
this.npc = npc;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the npc that started looking at a player
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player who npc started looking at
|
||||
*/
|
||||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Is fired when NPC stops looking at a player.
|
||||
*/
|
||||
public class NpcStopLookingEvent extends Event {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
@NotNull
|
||||
private final Npc npc;
|
||||
@NotNull
|
||||
private final Player player;
|
||||
|
||||
public NpcStopLookingEvent(@NotNull Npc npc, @NotNull Player player) {
|
||||
this.npc = npc;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the npc that stopped looking at a player
|
||||
*/
|
||||
public @NotNull Npc getNpc() {
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player who npc stopped looking at
|
||||
*/
|
||||
public @NotNull Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Is fired when all NPCs are loaded.
|
||||
*
|
||||
* Will be removed, once the npc loading is coupled with the loading of worlds! Be aware of that!
|
||||
*/
|
||||
@ApiStatus.Experimental()
|
||||
public class NpcsLoadedEvent extends Event {
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancynpcs.api.events;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PacketReceivedEvent extends Event {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
|
||||
private final Object packet;
|
||||
private final Player player;
|
||||
|
||||
public PacketReceivedEvent(Object packet, Player player) {
|
||||
this.packet = packet;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
public Object getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package de.oliver.fancynpcs.api.skins;
|
||||
|
||||
public class SkinData {
|
||||
|
||||
private String identifier;
|
||||
private SkinVariant variant;
|
||||
|
||||
private String textureValue;
|
||||
private String textureSignature;
|
||||
|
||||
public SkinData(String identifier, SkinVariant variant, String textureValue, String textureSignature) {
|
||||
this.identifier = identifier;
|
||||
this.variant = variant;
|
||||
this.textureValue = textureValue;
|
||||
this.textureSignature = textureSignature;
|
||||
}
|
||||
|
||||
public SkinData(String identifier, SkinVariant variant) {
|
||||
this(identifier, variant, null, null);
|
||||
}
|
||||
|
||||
public boolean hasTexture() {
|
||||
return textureValue != null &&
|
||||
textureSignature != null &&
|
||||
!textureValue.isEmpty() &&
|
||||
!textureSignature.isEmpty();
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public SkinVariant getVariant() {
|
||||
return variant;
|
||||
}
|
||||
|
||||
public void setVariant(SkinVariant variant) {
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
public String getTextureValue() {
|
||||
return textureValue;
|
||||
}
|
||||
|
||||
public void setTextureValue(String textureValue) {
|
||||
this.textureValue = textureValue;
|
||||
}
|
||||
|
||||
public String getTextureSignature() {
|
||||
return textureSignature;
|
||||
}
|
||||
|
||||
public void setTextureSignature(String textureSignature) {
|
||||
this.textureSignature = textureSignature;
|
||||
}
|
||||
|
||||
public enum SkinVariant {
|
||||
AUTO,
|
||||
SLIM,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package de.oliver.fancynpcs.api.skins;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Event that is called when a skin is generated
|
||||
*/
|
||||
public class SkinGeneratedEvent extends Event {
|
||||
|
||||
private static final HandlerList handlerList = new HandlerList();
|
||||
|
||||
@NotNull
|
||||
private final String id;
|
||||
|
||||
@Nullable
|
||||
private final SkinData skin;
|
||||
|
||||
public SkinGeneratedEvent(@NotNull String id, @Nullable SkinData skin) {
|
||||
super(!Bukkit.isPrimaryThread());
|
||||
this.id = id;
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlerList;
|
||||
}
|
||||
|
||||
public @NotNull String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the skin that was generated
|
||||
*
|
||||
* @return the skin that was generated or null if the skin could not be generated
|
||||
*/
|
||||
public @Nullable SkinData getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return handlerList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.oliver.fancynpcs.api.skins;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface SkinManager {
|
||||
|
||||
/**
|
||||
* Fetch a skin by its identifier and variant
|
||||
*
|
||||
* @param identifier either a valid UUID, username, URL or file path
|
||||
* @return the skin data, if the skin was cached. Otherwise, null is returned and the skin is fetched asynchronously. You can listen to the {@link SkinGeneratedEvent} to get the skin data
|
||||
*/
|
||||
SkinData getByIdentifier(String identifier, SkinData.SkinVariant variant);
|
||||
|
||||
/**
|
||||
* Fetch a skin by a UUID of a player
|
||||
*
|
||||
* @return the skin data, if the skin was cached. Otherwise, null is returned and the skin is fetched asynchronously. You can listen to the {@link SkinGeneratedEvent} to get the skin data
|
||||
*/
|
||||
SkinData getByUUID(UUID uuid, SkinData.SkinVariant variant);
|
||||
|
||||
/**
|
||||
* Fetch a skin by a username of a player
|
||||
*
|
||||
* @return the skin data, if the skin was cached. Otherwise, null is returned and the skin is fetched asynchronously. You can listen to the {@link SkinGeneratedEvent} to get the skin data
|
||||
*/
|
||||
SkinData getByUsername(String username, SkinData.SkinVariant variant);
|
||||
|
||||
/**
|
||||
* Fetch a skin by a URL pointing to a skin image
|
||||
*
|
||||
* @return the skin data, if the skin was cached. Otherwise, null is returned and the skin is fetched asynchronously. You can listen to the {@link SkinGeneratedEvent} to get the skin data
|
||||
*/
|
||||
SkinData getByURL(String url, SkinData.SkinVariant variant);
|
||||
|
||||
/**
|
||||
* Fetch a skin by a file path pointing to a skin image (relative to plugins/FancyNPCs/skins)
|
||||
*
|
||||
* @return the skin data, if the skin was cached. Otherwise, null is returned and the skin is fetched asynchronously. You can listen to the {@link SkinGeneratedEvent} to get the skin data
|
||||
*/
|
||||
SkinData getByFile(String filePath, SkinData.SkinVariant variant);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Grabsky <44530932+Grabsky@users.noreply.github.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* HORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package de.oliver.fancynpcs.api.utils;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import static de.oliver.fancynpcs.api.utils.Interval.Unit.*;
|
||||
|
||||
|
||||
/**
|
||||
* {@link Interval} is simple (but not very extensible) object that provides methods for
|
||||
* unit conversion and creation of human-readable 'elapsed time' strings.
|
||||
* <p>
|
||||
* This API is for internal use only and can change at any time.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public final class Interval {
|
||||
|
||||
private final long value;
|
||||
|
||||
public Interval(final long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Interval} object of current time.
|
||||
*/
|
||||
public static @NotNull Interval now() {
|
||||
return new Interval(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Interval} object constructed from provided {@link Long long} {@code (interval)}.
|
||||
* It is expected that provided value is <u>already</u> a difference between two timestamps.
|
||||
*/
|
||||
public static @NotNull Interval of(final long interval, final @NotNull Unit unit) {
|
||||
return new Interval(interval * unit.factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Interval} object constructed from provided {@link Double double} {@code (interval)}.
|
||||
* It is expected that provided value is <u>already</u> a difference between two timestamps.
|
||||
*/
|
||||
public static @NotNull Interval of(final double interval, final @NotNull Unit unit) {
|
||||
return new Interval(Math.round(interval * unit.factor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Interval} of time between {@code n} and {@code m}.
|
||||
*/
|
||||
public static @NotNull Interval between(final long n, final long m, final @NotNull Unit unit) {
|
||||
return new Interval((n - m) * unit.factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Interval} of time between {@code n} and {@code m}.
|
||||
*/
|
||||
public static @NotNull Interval between(final double n, final double m, final @NotNull Unit unit) {
|
||||
return new Interval(Math.round((n - m) * unit.factor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns interval converted to specified {@link Unit} {@code (unit)}. <br />
|
||||
* <pre>
|
||||
* Interval.of(1500, Interval.Unit.MILLISECONDS).as(Interval.Unit.SECONDS) // 1.5F
|
||||
* Interval.of(300, Interval.Unit.SECONDS).as(Interval.Unit.MINUTES) // 5F
|
||||
* </pre>
|
||||
*/
|
||||
public double as(final @NotNull Unit unit) {
|
||||
return (double) (value / unit.factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} added.
|
||||
*/
|
||||
public @NotNull Interval add(final @NotNull Interval other) {
|
||||
return new Interval(this.value + other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} added.
|
||||
*/
|
||||
public @NotNull Interval add(final long n, final @NotNull Unit unit) {
|
||||
return new Interval(this.value + (n * unit.factor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} removed.
|
||||
*/
|
||||
public @NotNull Interval remove(final @NotNull Interval other) {
|
||||
return new Interval(this.value - other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of (this) {@link Interval} with {@code n} of {@link Unit} removed.
|
||||
*/
|
||||
public @NotNull Interval remove(final long n, final @NotNull Unit unit) {
|
||||
return new Interval(this.value - (n * unit.factor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new {@link Date} created from (this) {@link Interval}.
|
||||
*/
|
||||
public @NotNull Date toDate() {
|
||||
return new Date(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new {@link Instant} created from (this) {@link Interval}.
|
||||
*/
|
||||
public @NotNull Instant toInstant() {
|
||||
return Instant.ofEpochMilli(this.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns formatted {@link String} expressing this {@link Interval}.
|
||||
* <pre>
|
||||
* final Interval i = Interval.between(lastJoinedMillis, currentTimeMillis, Interval.Unit.MILLISECONDS);
|
||||
* System.out.println(i.toString()) + " ago"; // eg. '1d 7h 32min 10s ago'
|
||||
* </pre>
|
||||
*/
|
||||
@Override
|
||||
public @NotNull String toString() {
|
||||
// Returning milliseconds for values below 1000. (less than one second)
|
||||
if (value < 1000)
|
||||
return value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() % MINUTES.getFactor() % SECONDS.getFactor() / MILLISECONDS.getFactor() + "ms";
|
||||
;
|
||||
// Calculation values, the ugly way.
|
||||
final long years = value / YEARS.getFactor();
|
||||
final long months = value % YEARS.getFactor() / MONTHS.getFactor();
|
||||
final long days = value % YEARS.getFactor() % MONTHS.getFactor() / DAYS.getFactor();
|
||||
final long hours = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() / HOURS.getFactor();
|
||||
final long minutes = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() / MINUTES.getFactor();
|
||||
final long seconds = value % YEARS.getFactor() % MONTHS.getFactor() % DAYS.getFactor() % HOURS.getFactor() % MINUTES.getFactor() / SECONDS.getFactor();
|
||||
// Creating a new output StringBuilder object.
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
// Appending to the StringBuilder.
|
||||
if (years > 0L) builder.append(years).append("y ");
|
||||
if (months > 0L) builder.append(months).append("mo ");
|
||||
if (days > 0L) builder.append(days).append("d ");
|
||||
if (hours > 0L) builder.append(hours).append("h ");
|
||||
if (minutes > 0L) builder.append(minutes).append("min ");
|
||||
if (seconds > 0L) builder.append(seconds).append("s");
|
||||
// Removing last character if a whitespace.
|
||||
if (builder.charAt(builder.length() - 1) == ' ')
|
||||
builder.deleteCharAt(builder.length() - 1);
|
||||
// Building a String and returning.
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public enum Unit {
|
||||
MILLISECONDS(1L, "ms"),
|
||||
TICKS(50L, "t"),
|
||||
SECONDS(1_000L, "s"),
|
||||
MINUTES(60_000L, "min"),
|
||||
HOURS(3_600_000L, "h"),
|
||||
DAYS(86_400_000L, "d"),
|
||||
MONTHS(2_629_800_000L, "mo"),
|
||||
YEARS(31_557_600_000L, "y");
|
||||
|
||||
private final long factor;
|
||||
private final String shortCode;
|
||||
|
||||
Unit(final long factor, final @NotNull String shortCode) {
|
||||
this.factor = factor;
|
||||
this.shortCode = shortCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Unit} or {@code null} from provided short code.
|
||||
*/
|
||||
public static @Nullable Unit fromShortCode(final @NotNull String shortCode) {
|
||||
// Iterating over all units and finding one that matches provided short code.
|
||||
for (final Unit unit : Unit.values())
|
||||
if (unit.shortCode.equalsIgnoreCase(shortCode) == true)
|
||||
return unit;
|
||||
// Unit has not been found. Returning null.
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getFactor() {
|
||||
return factor;
|
||||
}
|
||||
|
||||
public @NotNull String getShortCode() {
|
||||
return shortCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.oliver.fancynpcs.api.utils;
|
||||
|
||||
public enum NpcEquipmentSlot {
|
||||
MAINHAND,
|
||||
OFFHAND,
|
||||
FEET,
|
||||
LEGS,
|
||||
CHEST,
|
||||
HEAD;
|
||||
|
||||
public static NpcEquipmentSlot parse(String s) {
|
||||
for (NpcEquipmentSlot slot : values()) {
|
||||
if (slot.name().equalsIgnoreCase(s)) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toNmsName() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
256
plugins/fancynpcs/build.gradle.kts
Normal file
@@ -0,0 +1,256 @@
|
||||
import net.minecrell.pluginyml.paper.PaperPluginDescription
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("xyz.jpenilla.run-paper")
|
||||
id("com.gradleup.shadow")
|
||||
id("net.minecrell.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"
|
||||
)
|
||||
|
||||
allprojects {
|
||||
group = "de.oliver"
|
||||
val buildId = System.getenv("BUILD_ID")
|
||||
version = "2.4.4" + (if (buildId != null) ".$buildId" else "")
|
||||
description = "Simple, lightweight and fast NPC plugin using packets"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven(url = "https://repo.papermc.io/repository/maven-public/")
|
||||
maven(url = "https://repo.fancyplugins.de/releases")
|
||||
maven(url = "https://repo.lushplugins.org/releases")
|
||||
maven(url = "https://repo.inventivetalent.org/repository/maven-snapshots/")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT")
|
||||
|
||||
implementation(project(":plugins:fancynpcs:api"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_21_5"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_21_4"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_21_3"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_21_1"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_20_6"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_20_4", configuration = "reobf"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_20_2", configuration = "reobf"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_20_1", configuration = "reobf"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_20", configuration = "reobf"))
|
||||
implementation(project(":plugins:fancynpcs:implementation_1_19_4", configuration = "reobf"))
|
||||
|
||||
implementation("de.oliver:FancyLib:37")
|
||||
implementation("de.oliver:plugin-tests:1.0.0")
|
||||
implementation("de.oliver:JDB:1.0.0")
|
||||
compileOnly("org.lushplugins:ChatColorHandler:5.1.3")
|
||||
implementation("de.oliver.FancyAnalytics:api:0.1.6")
|
||||
implementation("de.oliver.FancyAnalytics:logger:0.0.6")
|
||||
implementation("org.incendo:cloud-core:2.1.0-SNAPSHOT")
|
||||
implementation("org.incendo:cloud-paper:2.0.0-SNAPSHOT")
|
||||
implementation("org.incendo:cloud-annotations:2.1.0-SNAPSHOT")
|
||||
annotationProcessor("org.incendo:cloud-annotations:2.1.0-SNAPSHOT")
|
||||
implementation("org.mineskin:java-client-jsoup:3.0.3-SNAPSHOT")
|
||||
|
||||
compileOnly("com.intellectualsites.plotsquared:plotsquared-core:7.5.1")
|
||||
}
|
||||
|
||||
paper {
|
||||
main = "de.oliver.fancynpcs.FancyNpcs"
|
||||
bootstrapper = "de.oliver.fancynpcs.loaders.FancyNpcsBootstrapper"
|
||||
loader = "de.oliver.fancynpcs.loaders.FancyNpcsLoader"
|
||||
foliaSupported = true
|
||||
version = rootProject.version.toString()
|
||||
description = "Simple, lightweight and fast NPC plugin using packets"
|
||||
apiVersion = "1.19"
|
||||
serverDependencies {
|
||||
register("PlaceholderAPI") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
register("MiniPlaceholders") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
register("PlotSquared") {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
runServer {
|
||||
minecraftVersion("1.21.5")
|
||||
|
||||
downloadPlugins {
|
||||
hangar("ViaVersion", "5.2.1")
|
||||
hangar("ViaBackwards", "5.2.1")
|
||||
hangar("PlaceholderAPI", "2.11.6")
|
||||
// modrinth("multiverse-core", "4.3.11")
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate("org.incendo", "de.oliver")
|
||||
relocate("org.lushplugins.chatcolorhandler", "de.oliver.fancynpcs.libs.chatcolorhandler")
|
||||
archiveClassifier.set("")
|
||||
dependsOn(":api:shadowJar")
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "fancypluginsReleases"
|
||||
url = uri("https://repo.fancyplugins.de/releases")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
|
||||
maven {
|
||||
name = "fancypluginsSnapshots"
|
||||
url = uri("https://repo.fancyplugins.de/snapshots")
|
||||
credentials(PasswordCredentials::class)
|
||||
authentication {
|
||||
isAllowInsecureProtocol = true
|
||||
create<BasicAuthentication>("basic")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
groupId = project.group.toString()
|
||||
artifactId = project.name
|
||||
version = project.version.toString()
|
||||
from(project.components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
options.release = 21
|
||||
// For cloud-annotations, see https://cloud.incendo.org/annotations/#command-components
|
||||
options.compilerArgs.add("-parameters")
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
}
|
||||
|
||||
processResources {
|
||||
filteringCharset = Charsets.UTF_8.name() // We want UTF-8 for everything
|
||||
|
||||
val props = mapOf(
|
||||
"description" to project.description,
|
||||
"version" to project.version,
|
||||
"hash" to getCurrentCommitHash(),
|
||||
"build" to (System.getenv("BUILD_ID") ?: "").ifEmpty { "undefined" }
|
||||
)
|
||||
|
||||
inputs.properties(props)
|
||||
|
||||
filesMatching("paper-plugin.yml") {
|
||||
expand(props)
|
||||
}
|
||||
|
||||
filesMatching("version.yml") {
|
||||
expand(props)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.publishAllPublicationsToHangar {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
|
||||
tasks.modrinth {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
|
||||
fun getCurrentCommitHash(): String {
|
||||
val process = ProcessBuilder("git", "rev-parse", "HEAD").start()
|
||||
val reader = BufferedReader(InputStreamReader(process.inputStream))
|
||||
val commitHash = reader.readLine()
|
||||
reader.close()
|
||||
process.waitFor()
|
||||
if (process.exitValue() == 0) {
|
||||
return commitHash ?: ""
|
||||
} else {
|
||||
throw IllegalStateException("Failed to retrieve the commit hash.")
|
||||
}
|
||||
}
|
||||
|
||||
fun getLastCommitMessage(): String {
|
||||
val process = ProcessBuilder("git", "log", "-1", "--pretty=%B").start()
|
||||
val reader = BufferedReader(InputStreamReader(process.inputStream))
|
||||
val commitMessage = reader.readLine()
|
||||
reader.close()
|
||||
process.waitFor()
|
||||
if (process.exitValue() == 0) {
|
||||
println("Commit message: $commitMessage")
|
||||
return commitMessage ?: ""
|
||||
} else {
|
||||
throw IllegalStateException("Failed to retrieve the commit message.")
|
||||
}
|
||||
}
|
||||
|
||||
hangarPublish {
|
||||
publications.register("plugin") {
|
||||
version = project.version as String
|
||||
id = "FancyNpcs"
|
||||
channel = "Alpha"
|
||||
|
||||
apiKey.set(System.getenv("HANGAR_PUBLISH_API_TOKEN"))
|
||||
|
||||
platforms {
|
||||
paper {
|
||||
jar = tasks.shadowJar.flatMap { it.archiveFile }
|
||||
platformVersions.set(supportedVersions)
|
||||
}
|
||||
}
|
||||
|
||||
changelog = getLastCommitMessage()
|
||||
}
|
||||
}
|
||||
|
||||
modrinth {
|
||||
token.set(System.getenv("MODRINTH_PUBLISH_API_TOKEN"))
|
||||
projectId.set("fancynpcs")
|
||||
versionNumber.set(project.version.toString())
|
||||
versionType.set("alpha")
|
||||
uploadFile.set(file("build/libs/${project.name}-${project.version}.jar"))
|
||||
gameVersions.addAll(supportedVersions)
|
||||
loaders.add("paper")
|
||||
loaders.add("folia")
|
||||
changelog.set(getLastCommitMessage())
|
||||
}
|
||||
BIN
plugins/fancynpcs/images/banner.png
Normal file
|
After Width: | Height: | Size: 252 KiB |
BIN
plugins/fancynpcs/images/screenshots/dave1.jpeg
Normal file
|
After Width: | Height: | Size: 543 KiB |
BIN
plugins/fancynpcs/images/screenshots/grabsky1.jpeg
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
plugins/fancynpcs/images/screenshots/niceron1.jpeg
Normal file
|
After Width: | Height: | Size: 939 KiB |
BIN
plugins/fancynpcs/images/screenshots/niceron2.jpeg
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
plugins/fancynpcs/images/screenshots/niceron3.jpeg
Normal file
|
After Width: | Height: | Size: 576 KiB |
BIN
plugins/fancynpcs/images/screenshots/oliver1.jpeg
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
plugins/fancynpcs/images/screenshots/oliver2.jpeg
Normal file
|
After Width: | Height: | Size: 140 KiB |
34
plugins/fancynpcs/implementation_1_19_4/build.gradle.kts
Normal file
@@ -0,0 +1,34 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("io.papermc.paperweight.userdev")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.19.4"
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("$minecraftVersion-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly(project(":plugins:fancynpcs:api"))
|
||||
compileOnly("de.oliver:FancyLib:37")
|
||||
compileOnly("org.lushplugins:ChatColorHandler:5.1.3")
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
named("assemble") {
|
||||
dependsOn(named("reobfJar"))
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 17
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.oliver.fancynpcs.v1_19_4;
|
||||
|
||||
public enum MappingKeys1_19_4 {
|
||||
|
||||
ENTITY_TYPE__FACTORY("bA"),
|
||||
SYNCHED_ENTITY_DATA__ITEMS_BY_ID("e"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__X("b"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__Y("c"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__Z("d"),
|
||||
CLIENTBOUND_PLAYER_INFO_UPDATE_PACKET__ENTRIES("b"),
|
||||
PANDA__DATA_ID_FLAGS("ca"),
|
||||
;
|
||||
|
||||
private final String mapping;
|
||||
|
||||
MappingKeys1_19_4(String mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
public String getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
package de.oliver.fancynpcs.v1_19_4;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
||||
import net.minecraft.world.entity.Display;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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.v1_19_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.lushplugins.chatcolorhandler.ModernChatColorHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Npc_1_19_4 extends Npc {
|
||||
|
||||
private final String localName;
|
||||
private final UUID uuid;
|
||||
private Entity npc;
|
||||
private Display.TextDisplay sittingVehicle;
|
||||
|
||||
public Npc_1_19_4(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, ""));
|
||||
((ServerPlayer) npc).gameProfile = gameProfile;
|
||||
} else {
|
||||
EntityType<?> nmsType = BuiltInRegistries.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(data.getType().getKey()));
|
||||
EntityType.EntityFactory factory = (EntityType.EntityFactory) ReflectionUtils.getValue(nmsType, MappingKeys1_19_4.ENTITY_TYPE__FACTORY.getMapping()); // 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.getLevel().getWorld().getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getSkinData() != null && data.getSkinData().hasTexture()) {
|
||||
String value = data.getSkinData().getTextureValue();
|
||||
String signature = data.getSkinData().getTextureSignature();
|
||||
|
||||
((ServerPlayer) npc).getGameProfile().getProperties().replaceValues(
|
||||
"textures",
|
||||
ImmutableList.of(new Property("textures", value, signature))
|
||||
);
|
||||
}
|
||||
|
||||
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, List.of(npcPlayer));
|
||||
if (data.isMirrorSkin()) {
|
||||
handleMirroredSkin(playerInfoPacket, serverPlayer);
|
||||
}
|
||||
serverPlayer.connection.send(playerInfoPacket);
|
||||
|
||||
if (data.isSpawnEntity()) {
|
||||
npc.setPos(data.getLocation().x(), data.getLocation().y(), data.getLocation().z());
|
||||
ClientboundAddPlayerPacket spawnPlayerPacket = new ClientboundAddPlayerPacket(npcPlayer);
|
||||
serverPlayer.connection.send(spawnPlayerPacket);
|
||||
}
|
||||
}
|
||||
|
||||
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(npc);
|
||||
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);
|
||||
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) {
|
||||
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().getName() : 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, List.of(npcPlayer));
|
||||
if (data.isMirrorSkin()) {
|
||||
handleMirroredSkin(playerInfoPacket, 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());
|
||||
|
||||
if (data.getEquipment() != null && data.getEquipment().size() > 0) {
|
||||
List<Pair<EquipmentSlot, ItemStack>> equipmentList = new ArrayList<>();
|
||||
|
||||
for (NpcEquipmentSlot slot : data.getEquipment().keySet()) {
|
||||
equipmentList.add(new Pair<>(EquipmentSlot.byName(slot.toNmsName()), CraftItemStack.asNMSCopy(data.getEquipment().get(slot))));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
data.applyAllAttributes(this);
|
||||
|
||||
refreshEntityData(player);
|
||||
|
||||
if (data.isSpawnEntity() && data.getLocation() != null) {
|
||||
move(player, true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshEntityData(Player player) {
|
||||
if (!isVisibleForPlayer.getOrDefault(player.getUniqueId(), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
|
||||
Int2ObjectMap<SynchedEntityData.DataItem<?>> itemsById = (Int2ObjectMap<SynchedEntityData.DataItem<?>>) ReflectionUtils.getValue(npc.getEntityData(), MappingKeys1_19_4.SYNCHED_ENTITY_DATA__ITEMS_BY_ID.getMapping()); // itemsById
|
||||
List<SynchedEntityData.DataValue<?>> entityData = new ArrayList<>();
|
||||
for (SynchedEntityData.DataItem<?> dataItem : itemsById.values()) {
|
||||
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);
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_19_4.CLIENTBOUND_TELEPORT_ENTITY_PACKET__X.getMapping(), data.getLocation().x()); // 'x'
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_19_4.CLIENTBOUND_TELEPORT_ENTITY_PACKET__Y.getMapping(), data.getLocation().y()); // 'y'
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_19_4.CLIENTBOUND_TELEPORT_ENTITY_PACKET__Z.getMapping(), data.getLocation().z()); // 'z'
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(sittingVehicle);
|
||||
serverPlayer.connection.send(addEntityPacket);
|
||||
|
||||
sittingVehicle.passengers = ImmutableList.of(npc);
|
||||
|
||||
ClientboundSetPassengersPacket packet = new ClientboundSetPassengersPacket(sittingVehicle);
|
||||
serverPlayer.connection.send(packet);
|
||||
}
|
||||
|
||||
private void handleMirroredSkin(ClientboundPlayerInfoUpdatePacket playerInfoUpdatePacket, ServerPlayer viewer) {
|
||||
if (!ServerLoginPacketListenerImpl.isValidUsername(viewer.getGameProfile().getName())) return;
|
||||
ClientboundPlayerInfoUpdatePacket.Entry entry = playerInfoUpdatePacket.entries().get(0);
|
||||
GameProfile profile = entry.profile();
|
||||
GameProfile newProfile = new GameProfile(profile.getId(), profile.getName());
|
||||
newProfile.getProperties().putAll(viewer.getGameProfile().getProperties());
|
||||
ClientboundPlayerInfoUpdatePacket.Entry newEntry = new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
entry.profileId(),
|
||||
newProfile,
|
||||
entry.listed(),
|
||||
entry.latency(),
|
||||
entry.gameMode(),
|
||||
entry.displayName(),
|
||||
entry.chatSession()
|
||||
);
|
||||
|
||||
ReflectionUtils.setValue(playerInfoUpdatePacket, "b", List.of(newEntry)); // 'entries'
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getEyeHeight() {
|
||||
return npc.getEyeHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityId() {
|
||||
return npc.getId();
|
||||
}
|
||||
|
||||
public Entity getNpc() {
|
||||
return npc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.oliver.fancynpcs.v1_19_4;
|
||||
|
||||
import de.oliver.fancylib.FancyLib;
|
||||
import de.oliver.fancylib.ReflectionUtils;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.events.PacketReceivedEvent;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import net.minecraft.network.protocol.game.ServerboundInteractPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketReader_1_19_4 implements Listener {
|
||||
|
||||
public static boolean inject(Player player) {
|
||||
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
|
||||
Channel channel = serverPlayer.connection.connection.channel;
|
||||
|
||||
if (channel.pipeline().get("PacketInjector") != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
channel.pipeline().addAfter("decoder", "PacketInjector", new MessageToMessageDecoder<ServerboundInteractPacket>() {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ServerboundInteractPacket msg, List<Object> out) {
|
||||
out.add(msg);
|
||||
|
||||
PacketReceivedEvent packetReceivedEvent = new PacketReceivedEvent(msg, player);
|
||||
FancyLib.getInstance().getScheduler().runTaskLater(null, 1L, packetReceivedEvent::callEvent);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPacketReceived(final PacketReceivedEvent event) {
|
||||
// Skipping packets other than ServerboundInteractPacket...
|
||||
if (!(event.getPacket() instanceof ServerboundInteractPacket interactPacket))
|
||||
return;
|
||||
// Getting NPC from entity identifier.
|
||||
final Npc npc = FancyNpcsPlugin.get().getNpcManager().getNpc(interactPacket.getEntityId());
|
||||
// Skipping entities that are not FancyNpcs' NPCs...
|
||||
if (npc == null)
|
||||
return;
|
||||
// Getting interaction information.
|
||||
final boolean isAttack = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.ATTACK);
|
||||
final boolean isInteract = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.INTERACT_AT);
|
||||
final EquipmentSlot hand = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.ATTACK)
|
||||
? EquipmentSlot.HAND
|
||||
: ReflectionUtils.getValue(ReflectionUtils.getValue(interactPacket, "b"), "a").toString().equals("MAIN_HAND") // ServerboundInteractPacket.InteractionAction.hand
|
||||
? EquipmentSlot.HAND
|
||||
: EquipmentSlot.OFF_HAND;
|
||||
// This can optionally be ALSO called for OFF-HAND slot. Making sure to run logic only ONCE.
|
||||
if (hand == EquipmentSlot.HAND) {
|
||||
// This packet can be sent multiple times for interactions that are NOT attacks, making sure to run logic only ONCE.
|
||||
if (isAttack || !isInteract || npc.getData().getType() == EntityType.ARMOR_STAND) {
|
||||
npc.interact(event.getPlayer(), isAttack ? ActionTrigger.LEFT_CLICK : ActionTrigger.RIGHT_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.oliver.fancynpcs.v1_19_4;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Attributes_1_19_4 {
|
||||
|
||||
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(ArmorStandAttributes.getAllAttributes());
|
||||
attributes.addAll(BeeAttributes.getAllAttributes());
|
||||
attributes.addAll(VexAttributes.getAllAttributes());
|
||||
|
||||
attributes.addAll(DisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(TextDisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(BlockDisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(InteractionAttributes.getAllAttributes());
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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.setRemainingPersistentAngerTime(1);
|
||||
case "false" -> bee.setRemainingPersistentAngerTime(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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
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;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class BlockDisplayAttributes {
|
||||
|
||||
private static final List<String> BLOCKS = StreamSupport.stream(Registry.MATERIAL.spliterator(), false).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.get(ResourceLocation.of("minecraft:" + value.toLowerCase(), ':'));
|
||||
|
||||
display.setBlockState(block.defaultBlockState());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.world.entity.animal.camel.Camel;
|
||||
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);
|
||||
|
||||
switch (value.toLowerCase()) {
|
||||
case "standing" -> {
|
||||
camel.setDashing(false);
|
||||
camel.standUp();
|
||||
}
|
||||
case "sitting" -> {
|
||||
camel.setDashing(false);
|
||||
camel.sitDown();
|
||||
}
|
||||
case "dashing" -> {
|
||||
camel.standUp();
|
||||
camel.setDashing(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.animal.Cat;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CatAttributes {
|
||||
|
||||
public static List<NpcAttribute> getAllAttributes() {
|
||||
List<NpcAttribute> attributes = new ArrayList<>();
|
||||
|
||||
attributes.add(new NpcAttribute(
|
||||
"variant",
|
||||
Arrays.stream(org.bukkit.entity.Cat.Type.values())
|
||||
.map(Enum::name)
|
||||
.toList(),
|
||||
List.of(EntityType.CAT),
|
||||
CatAttributes::setVariant
|
||||
));
|
||||
|
||||
attributes.add(new NpcAttribute(
|
||||
"pose",
|
||||
List.of("standing", "sleeping", "sitting"),
|
||||
List.of(EntityType.CAT),
|
||||
CatAttributes::setPose
|
||||
));
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void setVariant(Npc npc, String value) {
|
||||
final Cat cat = ReflectionHelper.getEntity(npc);
|
||||
BuiltInRegistries.CAT_VARIANT.getOptional(ResourceLocation.of(value.toLowerCase(), ':'))
|
||||
.ifPresent(cat::setVariant);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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.Type.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.Type type = Fox.Type.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.world.entity.animal.FrogVariant;
|
||||
import net.minecraft.world.entity.animal.frog.Frog;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FrogAttributes {
|
||||
|
||||
public static List<NpcAttribute> getAllAttributes() {
|
||||
List<NpcAttribute> attributes = new ArrayList<>();
|
||||
|
||||
attributes.add(new NpcAttribute(
|
||||
"variant",
|
||||
Arrays.stream(org.bukkit.entity.Frog.Variant.values())
|
||||
.map(Enum::name)
|
||||
.toList(),
|
||||
List.of(EntityType.FROG),
|
||||
FrogAttributes::setVariant
|
||||
));
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void setVariant(Npc npc, String value) {
|
||||
Frog frog = ReflectionHelper.getEntity(npc);
|
||||
|
||||
FrogVariant variant;
|
||||
switch (value.toUpperCase()) {
|
||||
case "COLD" -> variant = FrogVariant.COLD;
|
||||
case "WARM" -> variant = FrogVariant.WARM;
|
||||
default -> variant = FrogVariant.TEMPERATE;
|
||||
}
|
||||
|
||||
frog.setVariant(variant);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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.setVariant(variant);
|
||||
}
|
||||
|
||||
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.setForceStanding(false);
|
||||
}
|
||||
case "rearing" -> {
|
||||
horse.setForceStanding(true);
|
||||
horse.setEating(false);
|
||||
}
|
||||
case "eating" -> {
|
||||
horse.setForceStanding(false);
|
||||
horse.setEating(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancylib.ReflectionUtils;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.MappingKeys1_19_4;
|
||||
import de.oliver.fancynpcs.v1_19_4.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, MappingKeys1_19_4.PANDA__DATA_ID_FLAGS.getMapping());
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.world.entity.animal.Pig;
|
||||
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(
|
||||
"has_saddle",
|
||||
List.of("true", "false"),
|
||||
List.of(EntityType.PIG),
|
||||
PigAttributes::setHasSaddle
|
||||
));
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void setHasSaddle(Npc npc, String value) {
|
||||
Pig pig = ReflectionHelper.getEntity(npc);
|
||||
|
||||
boolean hasSaddle = Boolean.parseBoolean(value.toLowerCase());
|
||||
|
||||
pig.steering.setSaddle(hasSaddle);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancylib.ReflectionUtils;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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, "ar"); // DATA_POSE
|
||||
player.getEntityData().set(DATA_POSE, pose);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.world.entity.animal.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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;
|
||||
import java.util.Optional;
|
||||
|
||||
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.setVariant(Optional.of(color));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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.setVariant(pattern);
|
||||
}
|
||||
|
||||
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.getVariant(), 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.getVariant(), tropicalFish.getBaseColor(), color);
|
||||
tropicalFish.setPackedVariant(variant.getPackedId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
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.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class VillagerAttributes {
|
||||
|
||||
public static List<NpcAttribute> getAllAttributes() {
|
||||
List<NpcAttribute> attributes = new ArrayList<>();
|
||||
|
||||
attributes.add(new NpcAttribute(
|
||||
"profession",
|
||||
Arrays.stream(org.bukkit.entity.Villager.Profession.values())
|
||||
.map(Enum::name)
|
||||
.toList(),
|
||||
List.of(EntityType.VILLAGER),
|
||||
VillagerAttributes::setProfession
|
||||
));
|
||||
|
||||
attributes.add(new NpcAttribute(
|
||||
"type",
|
||||
Arrays.stream(org.bukkit.entity.Villager.Type.values())
|
||||
.map(Enum::name)
|
||||
.toList(),
|
||||
List.of(EntityType.VILLAGER),
|
||||
VillagerAttributes::setType
|
||||
));
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static void setProfession(Npc npc, String value) {
|
||||
Villager villager = ReflectionHelper.getEntity(npc);
|
||||
|
||||
VillagerProfession profession;
|
||||
switch (value.toUpperCase()) {
|
||||
case "ARMORER" -> profession = VillagerProfession.ARMORER;
|
||||
case "BUTCHER" -> profession = VillagerProfession.BUTCHER;
|
||||
case "CARTOGRAPHER" -> profession = VillagerProfession.CARTOGRAPHER;
|
||||
case "CLERIC" -> profession = VillagerProfession.CLERIC;
|
||||
case "FARMER" -> profession = VillagerProfession.FARMER;
|
||||
case "FISHERMAN" -> profession = VillagerProfession.FISHERMAN;
|
||||
case "FLETCHER" -> profession = VillagerProfession.FLETCHER;
|
||||
case "LEATHERWORKER" -> profession = VillagerProfession.LEATHERWORKER;
|
||||
case "LIBRARIAN" -> profession = VillagerProfession.LIBRARIAN;
|
||||
case "MASON" -> profession = VillagerProfession.MASON;
|
||||
case "NITWIT" -> profession = VillagerProfession.NITWIT;
|
||||
case "SHEPHERD" -> profession = VillagerProfession.SHEPHERD;
|
||||
case "TOOLSMITH" -> profession = VillagerProfession.TOOLSMITH;
|
||||
case "WEAPONSMITH" -> profession = VillagerProfession.WEAPONSMITH;
|
||||
|
||||
default -> profession = VillagerProfession.NONE;
|
||||
}
|
||||
|
||||
villager.setVillagerData(villager.getVillagerData().setProfession(profession));
|
||||
}
|
||||
|
||||
private static void setType(Npc npc, String value) {
|
||||
Villager villager = ReflectionHelper.getEntity(npc);
|
||||
|
||||
VillagerType type;
|
||||
switch (value.toUpperCase()) {
|
||||
case "DESERT" -> type = VillagerType.DESERT;
|
||||
case "JUNGLE" -> type = VillagerType.JUNGLE;
|
||||
case "SAVANNA" -> type = VillagerType.SAVANNA;
|
||||
case "SNOW" -> type = VillagerType.SNOW;
|
||||
case "SWAMP" -> type = VillagerType.SWAMP;
|
||||
case "TAIGA" -> type = VillagerType.TAIGA;
|
||||
|
||||
default -> type = VillagerType.PLAINS;
|
||||
}
|
||||
|
||||
|
||||
villager.setVillagerData(villager.getVillagerData().setType(type));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package de.oliver.fancynpcs.v1_19_4.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_19_4.ReflectionHelper;
|
||||
import net.minecraft.world.entity.animal.Wolf;
|
||||
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
|
||||
));
|
||||
|
||||
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.setRemainingPersistentAngerTime(angry ? 100 : 0);
|
||||
}
|
||||
}
|
||||
31
plugins/fancynpcs/implementation_1_20/build.gradle.kts
Normal file
@@ -0,0 +1,31 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("io.papermc.paperweight.userdev")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.20"
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("$minecraftVersion-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly(project(":plugins:fancynpcs:api"))
|
||||
compileOnly("de.oliver:FancyLib:37")
|
||||
compileOnly("org.lushplugins:ChatColorHandler:5.1.3")
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
named("assemble") {
|
||||
dependsOn(named("reobfJar"))
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 17
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package de.oliver.fancynpcs.v1_20;
|
||||
|
||||
import de.oliver.fancylib.FancyLib;
|
||||
import de.oliver.fancylib.ReflectionUtils;
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.actions.ActionTrigger;
|
||||
import de.oliver.fancynpcs.api.events.PacketReceivedEvent;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import net.minecraft.network.protocol.game.ServerboundInteractPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PacketReader_1_20 implements Listener {
|
||||
|
||||
public static boolean inject(Player player) {
|
||||
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
|
||||
Channel channel = serverPlayer.connection.connection.channel;
|
||||
|
||||
if (channel.pipeline().get("PacketInjector") != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
channel.pipeline().addAfter("decoder", "PacketInjector", new MessageToMessageDecoder<ServerboundInteractPacket>() {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ServerboundInteractPacket msg, List<Object> out) {
|
||||
out.add(msg);
|
||||
|
||||
PacketReceivedEvent packetReceivedEvent = new PacketReceivedEvent(msg, player);
|
||||
FancyLib.getInstance().getScheduler().runTaskLater(null, 1L, packetReceivedEvent::callEvent);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPacketReceived(final PacketReceivedEvent event) {
|
||||
// Skipping packets other than ServerboundInteractPacket...
|
||||
if (!(event.getPacket() instanceof ServerboundInteractPacket interactPacket))
|
||||
return;
|
||||
// Getting entity identifier.
|
||||
final int entityId = interactPacket.getEntityId();
|
||||
// Getting NPC from entity identifier.
|
||||
final Npc npc = FancyNpcsPlugin.get().getNpcManager().getNpc(entityId);
|
||||
// Skipping entities that are not FancyNpcs' NPCs...
|
||||
if (npc == null)
|
||||
return;
|
||||
// Getting interaction information.
|
||||
final boolean isAttack = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.ATTACK);
|
||||
final boolean isInteract = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.INTERACT_AT);
|
||||
final EquipmentSlot hand = (interactPacket.getActionType() == ServerboundInteractPacket.ActionType.ATTACK)
|
||||
? EquipmentSlot.HAND
|
||||
: ReflectionUtils.getValue(ReflectionUtils.getValue(interactPacket, "b"), "a").toString().equals("MAIN_HAND") // ServerboundInteractPacket.InteractionAction.hand
|
||||
? EquipmentSlot.HAND
|
||||
: EquipmentSlot.OFF_HAND;
|
||||
// This can optionally be ALSO called for OFF-HAND slot. Making sure to run logic only ONCE.
|
||||
if (hand == EquipmentSlot.HAND) {
|
||||
// This packet can be sent multiple times for interactions that are NOT attacks, making sure to run logic only ONCE.
|
||||
if (isAttack || !isInteract || npc.getData().getType() == EntityType.ARMOR_STAND) {
|
||||
npc.interact(event.getPlayer(), isAttack ? ActionTrigger.LEFT_CLICK : ActionTrigger.RIGHT_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
31
plugins/fancynpcs/implementation_1_20_1/build.gradle.kts
Normal file
@@ -0,0 +1,31 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("io.papermc.paperweight.userdev")
|
||||
}
|
||||
|
||||
val minecraftVersion = "1.20.1"
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("$minecraftVersion-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly(project(":plugins:fancynpcs:api"))
|
||||
compileOnly("de.oliver:FancyLib:37")
|
||||
compileOnly("org.lushplugins:ChatColorHandler:5.1.3")
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
named("assemble") {
|
||||
dependsOn(named("reobfJar"))
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release = 17
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.oliver.fancynpcs.v1_20_1;
|
||||
|
||||
public enum MappingKeys1_20_1 {
|
||||
|
||||
ENTITY_TYPE__FACTORY("bA"),
|
||||
SYNCHED_ENTITY_DATA__ITEMS_BY_ID("e"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__X("b"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__Y("c"),
|
||||
CLIENTBOUND_TELEPORT_ENTITY_PACKET__Z("d"),
|
||||
CLIENTBOUND_PLAYER_INFO_UPDATE_PACKET__ENTRIES("b"),
|
||||
PANDA__DATA_ID_FLAGS("cb"),
|
||||
;
|
||||
|
||||
private final String mapping;
|
||||
|
||||
MappingKeys1_20_1(String mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
public String getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
package de.oliver.fancynpcs.v1_20_1;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.Optionull;
|
||||
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.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Display;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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.v1_20_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.lushplugins.chatcolorhandler.ModernChatColorHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Npc_1_20_1 extends Npc {
|
||||
|
||||
private final String localName;
|
||||
private final UUID uuid;
|
||||
private Entity npc;
|
||||
private Display.TextDisplay sittingVehicle;
|
||||
|
||||
public Npc_1_20_1(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, ""));
|
||||
((ServerPlayer) npc).gameProfile = gameProfile;
|
||||
} else {
|
||||
EntityType<?> nmsType = BuiltInRegistries.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(data.getType().getKey()));
|
||||
EntityType.EntityFactory factory = (EntityType.EntityFactory) ReflectionUtils.getValue(nmsType, MappingKeys1_20_1.ENTITY_TYPE__FACTORY.getMapping()); // 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();
|
||||
|
||||
((ServerPlayer) npc).getGameProfile().getProperties().replaceValues(
|
||||
"textures",
|
||||
ImmutableList.of(new Property("textures", value, signature))
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// The constructor ClientboundPlayerInfoUpdatePacket(actions, entries) is not available in 1.20
|
||||
ClientboundPlayerInfoUpdatePacket playerInfoPacket = new ClientboundPlayerInfoUpdatePacket(actions, List.of(npcPlayer)); // KEEP
|
||||
List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(getEntry(npcPlayer, serverPlayer)); // KEEP
|
||||
ReflectionUtils.setValue(playerInfoPacket, MappingKeys1_20_1.CLIENTBOUND_PLAYER_INFO_UPDATE_PACKET__ENTRIES.getMapping(), entries); // KEEP
|
||||
serverPlayer.connection.send(playerInfoPacket);
|
||||
|
||||
if (data.isSpawnEntity()) {
|
||||
npc.setPos(data.getLocation().x(), data.getLocation().y(), data.getLocation().z());
|
||||
ClientboundAddPlayerPacket spawnPlayerPacket = new ClientboundAddPlayerPacket(npcPlayer); // # keep!
|
||||
serverPlayer.connection.send(spawnPlayerPacket); // # keep!
|
||||
}
|
||||
}
|
||||
|
||||
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(npc); // # keep!
|
||||
serverPlayer.connection.send(addEntityPacket); // # keep!
|
||||
|
||||
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);
|
||||
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) {
|
||||
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().getName() : 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());
|
||||
|
||||
if (data.getEquipment() != null && data.getEquipment().size() > 0) {
|
||||
List<Pair<EquipmentSlot, ItemStack>> equipmentList = new ArrayList<>();
|
||||
|
||||
for (NpcEquipmentSlot slot : data.getEquipment().keySet()) {
|
||||
equipmentList.add(new Pair<>(EquipmentSlot.byName(slot.toNmsName()), CraftItemStack.asNMSCopy(data.getEquipment().get(slot))));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
data.applyAllAttributes(this);
|
||||
|
||||
refreshEntityData(player);
|
||||
|
||||
if (data.isSpawnEntity() && data.getLocation() != null) {
|
||||
move(player, true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshEntityData(Player player) {
|
||||
if (!isVisibleForPlayer.getOrDefault(player.getUniqueId(), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
|
||||
Int2ObjectMap<SynchedEntityData.DataItem<?>> itemsById = (Int2ObjectMap<SynchedEntityData.DataItem<?>>) ReflectionUtils.getValue(npc.getEntityData(), MappingKeys1_20_1.SYNCHED_ENTITY_DATA__ITEMS_BY_ID.getMapping()); // itemsById
|
||||
List<SynchedEntityData.DataValue<?>> entityData = new ArrayList<>();
|
||||
for (SynchedEntityData.DataItem<?> dataItem : itemsById.values()) {
|
||||
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);
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_20_1.CLIENTBOUND_TELEPORT_ENTITY_PACKET__X.getMapping(), data.getLocation().x()); // 'x'
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_20_1.CLIENTBOUND_TELEPORT_ENTITY_PACKET__Y.getMapping(), data.getLocation().y()); // 'y'
|
||||
ReflectionUtils.setValue(teleportEntityPacket, MappingKeys1_20_1.CLIENTBOUND_TELEPORT_ENTITY_PACKET__Z.getMapping(), data.getLocation().z()); // 'z'
|
||||
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 = npcPlayer.getGameProfile();
|
||||
if (data.isMirrorSkin() && viewer.getGameProfile().getProperties().containsKey("textures")) {
|
||||
GameProfile newProfile = new GameProfile(profile.getId(), profile.getName());
|
||||
newProfile.getProperties().putAll(viewer.getGameProfile().getProperties());
|
||||
profile = newProfile;
|
||||
}
|
||||
|
||||
return new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
npcPlayer.getUUID(),
|
||||
profile,
|
||||
data.isShowInTab(),
|
||||
npcPlayer.latency,
|
||||
npcPlayer.gameMode.getGameModeForPlayer(),
|
||||
npcPlayer.getTabListDisplayName(),
|
||||
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());
|
||||
|
||||
ClientboundAddEntityPacket addEntityPacket = new ClientboundAddEntityPacket(sittingVehicle);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package de.oliver.fancynpcs.v1_20_1;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Attributes_1_20_1 {
|
||||
|
||||
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(ArmorStandAttributes.getAllAttributes());
|
||||
attributes.addAll(BeeAttributes.getAllAttributes());
|
||||
attributes.addAll(VexAttributes.getAllAttributes());
|
||||
|
||||
attributes.addAll(DisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(TextDisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(BlockDisplayAttributes.getAllAttributes());
|
||||
attributes.addAll(InteractionAttributes.getAllAttributes());
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.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.setRemainingPersistentAngerTime(1);
|
||||
case "false" -> bee.setRemainingPersistentAngerTime(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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.ReflectionHelper;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
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;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class BlockDisplayAttributes {
|
||||
|
||||
private static final List<String> BLOCKS = StreamSupport.stream(Registry.MATERIAL.spliterator(), false).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.get(ResourceLocation.of("minecraft:" + value.toLowerCase(), ':'));
|
||||
|
||||
display.setBlockState(block.defaultBlockState());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package de.oliver.fancynpcs.v1_20_1.attributes;
|
||||
|
||||
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
|
||||
import de.oliver.fancynpcs.api.Npc;
|
||||
import de.oliver.fancynpcs.api.NpcAttribute;
|
||||
import de.oliver.fancynpcs.v1_20_1.ReflectionHelper;
|
||||
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.setDashing(false);
|
||||
camel.standUp();
|
||||
}
|
||||
case "sitting" -> {
|
||||
camel.setDashing(false);
|
||||
camel.sitDown();
|
||||
}
|
||||
case "dashing" -> {
|
||||
camel.standUpInstantly();
|
||||
camel.setDashing(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||