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

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

View File

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

View File

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

View File

@@ -1 +1 @@
2.7.1.299
2.8.0.308

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ import de.oliver.fancynpcs.v1_20_2.attributes.Attributes_1_20_2;
import de.oliver.fancynpcs.v1_20_4.attributes.Attributes_1_20_4;
import de.oliver.fancynpcs.v1_20_6.attributes.Attributes_1_20_5;
import de.oliver.fancynpcs.v1_21_1.attributes.Attributes_1_21_1;
import de.oliver.fancynpcs.v1_21_11.attributes.Attributes_1_21_11;
import de.oliver.fancynpcs.v1_21_3.attributes.Attributes_1_21_3;
import de.oliver.fancynpcs.v1_21_4.attributes.Attributes_1_21_4;
import de.oliver.fancynpcs.v1_21_5.attributes.Attributes_1_21_5;
@@ -31,6 +32,7 @@ public class AttributeManagerImpl implements AttributeManager {
private void init() {
String mcVersion = Bukkit.getMinecraftVersion();
switch (mcVersion) {
case "1.21.11" -> attributes = Attributes_1_21_11.getAllAttributes();
case "1.21.9", "1.21.10" -> attributes = Attributes_1_21_9.getAllAttributes();
case "1.21.6", "1.21.7", "1.21.8" -> attributes = Attributes_1_21_6.getAllAttributes();
case "1.21.5" -> attributes = Attributes_1_21_5.getAllAttributes();

View File

@@ -53,6 +53,7 @@ import de.oliver.fancynpcs.v1_20_2.Npc_1_20_2;
import de.oliver.fancynpcs.v1_20_4.Npc_1_20_4;
import de.oliver.fancynpcs.v1_20_6.Npc_1_20_6;
import de.oliver.fancynpcs.v1_21_1.Npc_1_21_1;
import de.oliver.fancynpcs.v1_21_11.Npc_1_21_11;
import de.oliver.fancynpcs.v1_21_3.Npc_1_21_3;
import de.oliver.fancynpcs.v1_21_4.Npc_1_21_4;
import de.oliver.fancynpcs.v1_21_5.Npc_1_21_5;
@@ -82,6 +83,7 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin {
public static final FeatureFlag USE_NATIVE_THREADS_FEATURE_FLAG = new FeatureFlag("use-native-threads", "Use native threads instead of virtual threads.", false);
public static final FeatureFlag ENABLE_DEBUG_MODE_FEATURE_FLAG = new FeatureFlag("enable-debug-mode", "Enable debug mode", false);
public static final FeatureFlag ENABLE_FOLIA_VISIBILITY_FIX_FEATURE_FLAG = new FeatureFlag("enable-folia-visibility-fix", "When enabled, all npcs will respawn after 100ms when they should spawn", false);
public static final FeatureFlag USE_MINECRAFT_USERCACHE_FEATURE_FLAG = new FeatureFlag("use-minecraft-usercache", "Include the content of usercache.json to the username->uuid cache", false);
private static FancyNpcs instance;
private final ExtendedFancyLogger fancyLogger;
@@ -163,6 +165,7 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin {
String mcVersion = Bukkit.getMinecraftVersion();
switch (mcVersion) {
case "1.21.11" -> npcAdapter = Npc_1_21_11::new;
case "1.21.9", "1.21.10" -> npcAdapter = Npc_1_21_9::new;
case "1.21.6", "1.21.7", "1.21.8" -> npcAdapter = Npc_1_21_6::new;
case "1.21.5" -> npcAdapter = Npc_1_21_5::new;
@@ -190,7 +193,7 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin {
fancyLogger.error("Unsupported minecraft server version.");
getLogger().warning("--------------------------------------------------");
getLogger().warning("Unsupported minecraft server version.");
getLogger().warning("This plugin only supports 1.19.4 - 1.21.8");
getLogger().warning("This plugin only supports 1.19.4 - 1.21.11");
getLogger().warning("Disabling the FancyNpcs plugin.");
getLogger().warning("--------------------------------------------------");
pluginManager.disablePlugin(this);
@@ -276,7 +279,7 @@ public class FancyNpcs extends JavaPlugin implements FancyNpcsPlugin {
pluginManager.registerEvents(new PlayerTeleportListener(), instance);
pluginManager.registerEvents(new PlayerChangedWorldListener(), instance);
pluginManager.registerEvents(skinManager, instance);
if (Bukkit.getMinecraftVersion().equals("1.21.4") || Bukkit.getMinecraftVersion().equals("1.21.5") || Bukkit.getMinecraftVersion().equals("1.21.6") || Bukkit.getMinecraftVersion().equals("1.21.7") || Bukkit.getMinecraftVersion().equals("1.21.8") || Bukkit.getMinecraftVersion().equals("1.21.9") || Bukkit.getMinecraftVersion().equals("1.21.10")) {
if (Set.of("1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11").contains(Bukkit.getMinecraftVersion())) {
getServer().getPluginManager().registerEvents(new PlayerLoadedListener(), this);
}

View File

@@ -78,6 +78,12 @@ public class FancyNpcsConfigImpl implements FancyNpcsConfig {
*/
private int removeNpcsFromPlayerlistDelay;
/**
* Whether MPCs should swing arm on update.
*/
private boolean swingArmOnUpdate;
/**
* The API key for the MineSkin API.
*/
@@ -139,6 +145,9 @@ public class FancyNpcsConfigImpl implements FancyNpcsConfig {
removeNpcsFromPlayerlistDelay = (int) ConfigHelper.getOrDefault(config, "remove_npcs_from_playerlist_delay", 2000);
config.setInlineComments("remove_npcs_from_playerlist_delay", List.of("The delay in milliseconds to remove NPCs from the player list. Increase this value if you have problems with skins not loading correctly when joining or switching worlds. You can set it to -1, if you don't have any npcs using the show_in_tab feature."));
swingArmOnUpdate = (boolean) ConfigHelper.getOrDefault(config, "swing_arm_on_update", true);
config.setInlineComments("swing_arm_on_update", List.of("Whether NPCs should swing arm on update."));
blockedCommands = (List<String>) ConfigHelper.getOrDefault(config, "blocked_commands", Arrays.asList("op", "ban"));
config.setInlineComments("blocked_commands", List.of("The commands that are blocked for NPCs in the message."));
@@ -231,6 +240,8 @@ public class FancyNpcsConfigImpl implements FancyNpcsConfig {
return removeNpcsFromPlayerlistDelay;
}
public boolean isSwingArmOnUpdate() { return swingArmOnUpdate; }
public String getMineSkinApiKey() {
if (mineskinApiKey.isEmpty()) {
return null;

View File

@@ -33,6 +33,7 @@ import org.incendo.cloud.parser.standard.EnumParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.Optional;
import static org.incendo.cloud.exception.handling.ExceptionHandler.unwrappingHandler;
@@ -184,6 +185,7 @@ public final class CloudCommandManager {
annotationParser.parse(NearbyCMD.INSTANCE);
annotationParser.parse(HelpCMD.INSTANCE);
annotationParser.parse(RemoveCMD.INSTANCE);
annotationParser.parse(RotateCMD.INSTANCE);
annotationParser.parse(ShowInTabCMD.INSTANCE);
annotationParser.parse(SkinCMD.INSTANCE);
annotationParser.parse(TeleportCMD.INSTANCE);
@@ -197,8 +199,7 @@ public final class CloudCommandManager {
annotationParser.parse(FancyNpcsDebugCMD.INSTANCE);
}
String mcVersion = Bukkit.getMinecraftVersion();
if (mcVersion.equals("1.20.5") || mcVersion.equals("1.20.6") || mcVersion.equals("1.21") || mcVersion.equals("1.21.1") || mcVersion.equals("1.21.2") || mcVersion.equals("1.21.3") || mcVersion.equals("1.21.4") || mcVersion.equals("1.21.5") || mcVersion.equals("1.21.6") || mcVersion.equals("1.21.7") || Bukkit.getMinecraftVersion().equals("1.21.8") || Bukkit.getMinecraftVersion().equals("1.21.9") || Bukkit.getMinecraftVersion().equals("1.21.10")) {
if (Set.of("1.20.5", "1.20.6", "1.21", "1.21.1", "1.21.2", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10", "1.21.11").contains(Bukkit.getMinecraftVersion())) {
annotationParser.parse(ScaleCMD.INSTANCE);
}

View File

@@ -0,0 +1,43 @@
package de.oliver.fancynpcs.commands.npc;
import de.oliver.fancylib.translations.Translator;
import de.oliver.fancynpcs.FancyNpcs;
import de.oliver.fancynpcs.api.Npc;
import de.oliver.fancynpcs.api.events.NpcModifyEvent;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.Permission;
import org.jetbrains.annotations.NotNull;
public enum RotateCMD {
INSTANCE;
private final Translator translator = FancyNpcs.getInstance().getTranslator();
@Command("npc rotate <npc> <yaw> <pitch>")
@Permission("fancynpcs.command.npc.rotate")
public void onRotate(
final @NotNull CommandSender sender,
final @NotNull Npc npc,
final float yaw,
final float pitch
) {
final Location currentLocation = npc.getData().getLocation();
final Location newLocation = currentLocation.clone();
newLocation.setYaw(yaw);
newLocation.setPitch(pitch);
if (new NpcModifyEvent(npc, NpcModifyEvent.NpcModification.ROTATION, new float[]{yaw, pitch}, sender).callEvent()) {
npc.getData().setLocation(newLocation);
npc.updateForAll();
translator.translate("npc_rotate_set_success")
.replace("npc", npc.getData().getName())
.replace("yaw", String.valueOf(yaw))
.replace("pitch", String.valueOf(pitch))
.send(sender);
} else {
translator.translate("command_npc_modification_cancelled").send(sender);
}
}
}

View File

@@ -55,6 +55,10 @@ public class UUIDFileCache implements UUIDCache {
}
private void loadMinecraftUsercache() {
if (!FancyNpcs.USE_MINECRAFT_USERCACHE_FEATURE_FLAG.isEnabled()) {
return;
}
if (!usercacheFile.exists()) {
FancyNpcs.getInstance().getFancyLogger().debug("Minecraft usercache file does not exist, skipping load.");
return;

View File

@@ -123,6 +123,7 @@ messages:
npc_move_to: "<dark_gray> <gray>Syntax: {primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]"
npc_nearby: "<dark_gray> <gray>Syntax: {primaryColor}/npc nearby {secondaryColor}[filters...]"
npc_remove: "<dark_gray> <gray>Syntax: {primaryColor}/npc remove {secondaryColor}(npc)"
npc_rotate: "<dark_gray> <gray>Syntax: {primaryColor}/npc rotate {secondaryColor}(npc) (yaw) (pitch)"
npc_show_in_tab: "<dark_gray> <gray>Syntax: {primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)"
npc_skin: "<dark_gray> <gray>Syntax: {primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | uuid | placeholder | url | file name) [--slim]"
npc_teleport: "<dark_gray> <gray>Syntax: {primaryColor}/npc teleport {secondaryColor}(npc)"
@@ -176,6 +177,7 @@ messages:
- "<dark_gray> <hover:show_text:'<gray>Teleports NPC to specified location.'>{primaryColor}/npc move_to {secondaryColor}(npc) (x) (y) (z) [world]"
- "<dark_gray> <hover:show_text:'<gray>Lists all NPCs in your world. Can be filtered and sorted.'>{primaryColor}/npc nearby {secondaryColor}[--radius] [--type] [--sort]"
- "<dark_gray> <hover:show_text:'<gray>Removes (deletes) specified NPC.'>{primaryColor}/npc remove {secondaryColor}(npc)"
- "<dark_gray> <hover:show_text:'<gray>Changes the rotation (yaw and pitch) of the NPC.'>{primaryColor}/npc rotate {secondaryColor}(npc) (yaw) (pitch)"
- "<dark_gray> <hover:show_text:'<gray>Changes the scale of the size of the NPC.'>{primaryColor}/npc scale {secondaryColor}(npc) (factor)"
- "<dark_gray> <hover:show_text:'<gray>Changes whether the NPC is shown in the player-list. This works only on NPCs of PLAYER type.<newline><newline>{errorColor}Re-connecting to the server might be required for changes to take effect.'>{primaryColor}/npc show_in_tab {secondaryColor}(npc) (state)"
- "<dark_gray> <hover:show_text:'<gray>Changes skin of the NPC.<newline><gray>Supports PlaceholderAPI and MiniPlaceholders.<newline><newline>{warningColor}@none <dark_gray>- <gray>removes the skin<newline>{warningColor}@mirror <dark_gray>- <gray>mirrors player skin<newline>{warningColor}(name) <dark_gray>- <gray>name of any player<newline>{warningColor}(url) <dark_gray>- <gray>url of the skin texture'>{primaryColor}/npc skin {secondaryColor}(npc) (@none | @mirror | name | url) [--slim]"
@@ -302,6 +304,9 @@ messages:
# Commands (npc remove)
npc_remove_success: "<dark_gray> <gray>NPC {warningColor}{npc}<gray> has been removed."
# Commands (npc rotate)
npc_rotate_set_success: "<dark_gray> <gray>NPC {warningColor}{npc}<gray> has been rotated to yaw {warningColor}{yaw}<gray> and pitch {warningColor}{pitch}<gray>."
# Commands (scale)
npc_scale_set_success: "<dark_gray> <gray>NPC {warningColor}{npc}<gray> has been scaled to {warningColor}{scale}<gray>."