From 9e13f754bc055edae92320c2efa528d7018cb89b Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 10:56:01 +0530 Subject: [PATCH 1/9] fix UpdateChecker --- .../src/main/java/lol/pyr/znpcsplus/updater/UpdateChecker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/updater/UpdateChecker.java b/plugin/src/main/java/lol/pyr/znpcsplus/updater/UpdateChecker.java index 0503347..29fce30 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/updater/UpdateChecker.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/updater/UpdateChecker.java @@ -50,6 +50,7 @@ public class UpdateChecker extends BukkitRunnable { int currentPart = Integer.parseInt(currentParts[i]); int newPart = Integer.parseInt(newParts[i]); if (newPart > currentPart) return Status.UPDATE_NEEDED; + if (newPart < currentPart) return Status.LATEST_VERSION; } if (newType.ordinal() > currentType.ordinal()) return Status.UPDATE_NEEDED; if (newType == currentType) { From eead4ced660d33dcd4f36fa97f3189fd49206253 Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 11:15:22 +0530 Subject: [PATCH 2/9] support for FancyNpcs conversion --- .../conversion/DataImporterRegistry.java | 3 + .../fancynpcs/FancyNpcsImporter.java | 183 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 plugin/src/main/java/lol/pyr/znpcsplus/conversion/fancynpcs/FancyNpcsImporter.java diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java index 1bb4372..1185eb4 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/DataImporterRegistry.java @@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.conversion; import lol.pyr.znpcsplus.config.ConfigManager; import lol.pyr.znpcsplus.conversion.citizens.CitizensImporter; +import lol.pyr.znpcsplus.conversion.fancynpcs.FancyNpcsImporter; import lol.pyr.znpcsplus.conversion.znpcs.ZNpcImporter; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl; @@ -34,6 +35,8 @@ public class DataImporterRegistry { packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ZNPCsPlusLegacy/data.json"), bungeeConnector))); register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, taskScheduler, packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "Citizens/saves.yml"), npcRegistry))); + register("fancynpcs", LazyLoader.of(() -> new FancyNpcsImporter(configManager, adventure, taskScheduler, + packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "FancyNpcs/npcs.yml"), npcRegistry))); } private void register(String id, LazyLoader loader) { diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/conversion/fancynpcs/FancyNpcsImporter.java b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/fancynpcs/FancyNpcsImporter.java new file mode 100644 index 0000000..c264300 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/conversion/fancynpcs/FancyNpcsImporter.java @@ -0,0 +1,183 @@ +package lol.pyr.znpcsplus.conversion.fancynpcs; + +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import lol.pyr.znpcsplus.api.interaction.InteractionType; +import lol.pyr.znpcsplus.api.skin.SkinDescriptor; +import lol.pyr.znpcsplus.config.ConfigManager; +import lol.pyr.znpcsplus.conversion.DataImporter; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; +import lol.pyr.znpcsplus.interaction.consolecommand.ConsoleCommandAction; +import lol.pyr.znpcsplus.interaction.message.MessageAction; +import lol.pyr.znpcsplus.interaction.playercommand.PlayerCommandAction; +import lol.pyr.znpcsplus.npc.*; +import lol.pyr.znpcsplus.packets.PacketFactory; +import lol.pyr.znpcsplus.scheduling.TaskScheduler; +import lol.pyr.znpcsplus.skin.SkinImpl; +import lol.pyr.znpcsplus.skin.cache.MojangSkinCache; +import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor; +import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor; +import lol.pyr.znpcsplus.util.LookType; +import lol.pyr.znpcsplus.util.NamedColor; +import lol.pyr.znpcsplus.util.NpcLocation; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.util.*; + +public class FancyNpcsImporter implements DataImporter { + private final ConfigManager configManager; + private final BukkitAudiences adventure; + private final TaskScheduler scheduler; + private final PacketFactory packetFactory; + private final LegacyComponentSerializer textSerializer; + private final NpcTypeRegistryImpl typeRegistry; + private final EntityPropertyRegistryImpl propertyRegistry; + private final MojangSkinCache skinCache; + private final File dataFile; + private final NpcRegistryImpl npcRegistry; + + public FancyNpcsImporter(ConfigManager configManager, BukkitAudiences adventure, + TaskScheduler taskScheduler, PacketFactory packetFactory, LegacyComponentSerializer textSerializer, + NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, MojangSkinCache skinCache, + File dataFile, NpcRegistryImpl npcRegistry) { + this.configManager = configManager; + this.adventure = adventure; + this.scheduler = taskScheduler; + this.packetFactory = packetFactory; + this.textSerializer = textSerializer; + this.typeRegistry = typeRegistry; + this.propertyRegistry = propertyRegistry; + this.skinCache = skinCache; + this.dataFile = dataFile; + this.npcRegistry = npcRegistry; + } + + @Override + public Collection importData() { + YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile); + ConfigurationSection npcsSection = config.getConfigurationSection("npcs"); + if (npcsSection == null) { + return Collections.emptyList(); + } + ArrayList entries = new ArrayList<>(); + npcsSection.getKeys(false).forEach(key -> { + ConfigurationSection npcSection = npcsSection.getConfigurationSection(key); + if (npcSection == null) { + return; + } + String name = npcSection.getString("name", "FancyNPC"); + UUID uuid = UUID.fromString(key); + String world = npcSection.getString("location.world"); + if (world == null) { + world = Bukkit.getWorlds().get(0).getName(); + } + NpcLocation location = new NpcLocation( + npcSection.getDouble("location.x"), + npcSection.getDouble("location.y"), + npcSection.getDouble("location.z"), + (float) npcSection.getDouble("location.yaw"), + (float) npcSection.getDouble("location.pitch") + ); + String typeString = npcSection.getString("type"); + NpcTypeImpl type = typeRegistry.getByName(typeString); + if (type == null) { + type = typeRegistry.getByName("player"); + } + NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, world, type, location); + npc.getType().applyDefaultProperties(npc); + + npc.getHologram().addTextLineComponent(textSerializer.deserialize(name)); + boolean glowing = npcSection.getBoolean("glowing", false); + if (glowing) { + NamedColor color; + try { + color = NamedColor.valueOf(npcSection.getString("glowingColor", "white")); + } catch (IllegalArgumentException ignored) { + color = NamedColor.WHITE; + } + EntityPropertyImpl property = propertyRegistry.getByName("glow", NamedColor.class); + npc.setProperty(property, color); + } + if (npcSection.getBoolean("turnToPlayer", false)) { + EntityPropertyImpl property = propertyRegistry.getByName("look", LookType.class); + npc.setProperty(property, LookType.CLOSEST_PLAYER); + } + if (npcSection.isConfigurationSection("skin")) { + ConfigurationSection skinSection = npcSection.getConfigurationSection("skin"); + String texture = skinSection.getString("value"); + String signature = skinSection.getString("signature"); + npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new SkinImpl(texture, signature))); + } + if (npcSection.isConfigurationSection("equipment")) { + ConfigurationSection equipmentSection = npcSection.getConfigurationSection("equipment"); + for (String slot : equipmentSection.getKeys(false)) { + ItemStack item = equipmentSection.getItemStack(slot); + if (item != null) { + npc.setProperty(propertyRegistry.getByName(getEquipmentPropertyName(slot), + com.github.retrooper.packetevents.protocol.item.ItemStack.class), SpigotConversionUtil.fromBukkitItemStack(item)); + } + } + } + if (npcSection.getBoolean("mirrorSkin")) { + npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new MirrorDescriptor(skinCache)); + } + List playerCommands = npcSection.getStringList("playerCommands"); + if (!playerCommands.isEmpty()) { + long cooldown = npcSection.getLong("interactionCooldown", 0); + for (String command : playerCommands) { + npc.addAction(new PlayerCommandAction(scheduler, command, InteractionType.ANY_CLICK, cooldown, 0)); + } + } + String serverCommand = npcSection.getString("serverCommand"); + if (serverCommand != null) { + long cooldown = npcSection.getLong("interactionCooldown", 0); + npc.addAction(new ConsoleCommandAction(scheduler, serverCommand, InteractionType.ANY_CLICK, cooldown, 0)); + } + List messages = npcSection.getStringList("messages"); + if (!messages.isEmpty()) { + long cooldown = npcSection.getLong("interactionCooldown", 0); + for (String message : messages) { + npc.addAction(new MessageAction(adventure, message, InteractionType.ANY_CLICK, textSerializer, cooldown, 0)); + } + } + String id = npcSection.getString("name"); + while (npcRegistry.getById(id) != null) { + id += "_"; + } + NpcEntryImpl entry = new NpcEntryImpl(id, npc); + entry.enableEverything(); + entries.add(entry); + }); + return entries; + } + + private String getEquipmentPropertyName(String slot) { + switch (slot) { + case "MAINHAND": + return "hand"; + case "OFFHAND": + return "offhand"; + case "FEET": + return "boots"; + case "LEGS": + return "leggings"; + case "CHEST": + return "chestplate"; + case "HEAD": + return "helmet"; + default: + return null; + } + } + + @Override + public boolean isValid() { + return dataFile.isFile(); + } +} From e6c00472b5b9b4d4bb2f85812eb230af3111cad3 Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 19:21:12 +0530 Subject: [PATCH 3/9] added camel_sitting property --- .../entity/EntityPropertyRegistryImpl.java | 4 ++- .../properties/CamelSittingProperty.java | 33 +++++++++++++++++++ .../znpcsplus/npc/NpcTypeRegistryImpl.java | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/CamelSittingProperty.java diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java index 013e2cc..b7eef77 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -612,7 +612,9 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return; // Camel - register(new BooleanProperty("bashing", 18, false, legacyBooleans)); + int camelIndex = 18; + register(new BooleanProperty("bashing", camelIndex++, false, legacyBooleans)); + register(new CamelSittingProperty(6, camelIndex)); // Sniffer register(new CustomTypeProperty<>("sniffer_state", 17, SnifferState.IDLING, EntityDataTypes.SNIFFER_STATE, state -> com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState.valueOf(state.name()))); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/CamelSittingProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/CamelSittingProperty.java new file mode 100644 index 0000000..2732c21 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/CamelSittingProperty.java @@ -0,0 +1,33 @@ +package lol.pyr.znpcsplus.entity.properties; + +import com.github.retrooper.packetevents.protocol.entity.data.EntityData; +import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes; +import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.PacketEntity; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class CamelSittingProperty extends EntityPropertyImpl { + private final int poseIndex; + private final int lastPoseTickIndex; + + public CamelSittingProperty(int poseIndex, int lastPoseTickIndex) { + super("camel_sitting", false, Boolean.class); + this.poseIndex = poseIndex; + this.lastPoseTickIndex = lastPoseTickIndex; + } + + @Override + public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { + boolean value = entity.getProperty(this); + if (value) { + properties.put(poseIndex, newEntityData(poseIndex, EntityDataTypes.ENTITY_POSE, EntityPose.SITTING)); + properties.put(lastPoseTickIndex, newEntityData(lastPoseTickIndex, EntityDataTypes.LONG, -1L)); + } else { + properties.put(poseIndex, newEntityData(poseIndex, EntityDataTypes.ENTITY_POSE, EntityPose.STANDING)); + properties.put(lastPoseTickIndex, newEntityData(lastPoseTickIndex, EntityDataTypes.LONG, 0L)); + } + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java index 2cc382f..1d197f3 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeRegistryImpl.java @@ -367,7 +367,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry { register(builder(p, "camel", EntityTypes.CAMEL) .setHologramOffset(0.25) - .addProperties("bashing")); + .addProperties("bashing", "camel_sitting")); } public Collection getAll() { From 60011168f27cdfb8ef407a0c528d37c46d39f65d Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 20:30:26 +0530 Subject: [PATCH 4/9] fix dinnerbone property for 1.12 and below --- .../pyr/znpcsplus/entity/properties/DinnerboneProperty.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java index b04fc87..dab1770 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/properties/DinnerboneProperty.java @@ -14,11 +14,13 @@ import java.util.Map; import java.util.Optional; public class DinnerboneProperty extends EntityPropertyImpl { + private final boolean optional; private final Object serialized; private final EntityDataType type; public DinnerboneProperty(boolean legacy, boolean optional) { super("dinnerbone", false, Boolean.class); + this.optional = optional; Component name = Component.text("Dinnerbone"); Object serialized = legacy ? AdventureSerializer.getLegacyGsonSerializer().serialize(name) : optional ? name : LegacyComponentSerializer.legacySection().serialize(name); @@ -28,6 +30,6 @@ public class DinnerboneProperty extends EntityPropertyImpl { @Override public void apply(Player player, PacketEntity entity, boolean isSpawned, Map properties) { - properties.put(2, new EntityData(2, type, entity.getProperty(this) ? serialized : null)); + properties.put(2, new EntityData(2, type, entity.getProperty(this) ? serialized : optional ? null : "")); } } From 5834906ec6267b2ec79c4e77f8a8e7cd403c754b Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 20:31:22 +0530 Subject: [PATCH 5/9] fix baby property for 1.8 --- .../pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java index b7eef77..ade327e 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -154,7 +154,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) babyIndex = 12; else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) babyIndex = 11; else babyIndex = 12; - register(new BooleanProperty("baby", babyIndex, false, legacyBooleans)); + if (ver.isOlderThan(ServerVersion.V_1_9)) { + register(new EncodedByteProperty<>("baby", false, babyIndex, obj -> (byte) (obj ? -1 : 0))); + } else { + register(new BooleanProperty("baby", babyIndex, false, legacyBooleans)); + } // Player register(new DummyProperty<>("skin", SkinDescriptor.class, false)); From 4e75868a737496706264930a6a2c66ae8bd3f424 Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Tue, 30 Apr 2024 20:47:55 +0530 Subject: [PATCH 6/9] villager_profession property for 1.13 and below --- .../znpcsplus/util/VillagerProfession.java | 39 ++++++++++++------- .../entity/EntityPropertyRegistryImpl.java | 13 +++++-- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java index f02a53c..939f425 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/VillagerProfession.java @@ -1,29 +1,40 @@ package lol.pyr.znpcsplus.util; public enum VillagerProfession { - NONE(0), - ARMORER(1), - BUTCHER(2), - CARTOGRAPHER(3), - CLERIC(4), - FARMER(5), - FISHERMAN(6), - FLETCHER(7), - LEATHER_WORKER(8), - LIBRARIAN(9), + NONE(0, 0), + ARMORER(1, 3), + BUTCHER(2, 4), + CARTOGRAPHER(3, 1), + CLERIC(4, 2), + FARMER(5, 0), + FISHERMAN(6, 0), + FLETCHER(7, 0), + LEATHER_WORKER(8, 4), + LIBRARIAN(9, 1), MASON(10), - NITWIT(11), - SHEPHERD(12), - TOOL_SMITH(13), - WEAPON_SMITH(14); + NITWIT(11, 5), + SHEPHERD(12, 0), + TOOL_SMITH(13, 3), + WEAPON_SMITH(14, 3); private final int id; + private final int legacyId; VillagerProfession(int id) { this.id = id; + this.legacyId = 0; + } + + VillagerProfession(int id, int legacyId) { + this.id = id; + this.legacyId = legacyId; } public int getId() { return id; } + + public int getLegacyId() { + return legacyId; + } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java index ade327e..adf1b35 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -373,6 +373,15 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { register(new EncodedByteProperty<>("sheep_color", DyeColor.WHITE, sheepIndex, DyeColor::getWoolData)); register(new BitsetProperty("sheep_sheared", sheepIndex, 0x10, false, legacyBooleans)); // no need to link because sheep_sheared is only visible when sheep_color is WHITE + // Villager + int villagerIndex; + if (ver.isOlderThan(ServerVersion.V_1_14)) { + if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) villagerIndex = 13; + else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) villagerIndex = 12; + else villagerIndex = 16; + register(new EncodedIntegerProperty<>("villager_profession", VillagerProfession.NONE, villagerIndex, VillagerProfession::getLegacyId)); + } + // Wolf int wolfIndex; if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) wolfIndex = 19; @@ -501,12 +510,8 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { register(new CustomTypeProperty<>("pose", 6, NpcPose.STANDING, EntityDataTypes.ENTITY_POSE, npcPose -> EntityPose.valueOf(npcPose.name()))); // Villager - final int villagerIndex; if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) villagerIndex = 18; else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) villagerIndex = 17; - else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) villagerIndex = 16; - else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) villagerIndex = 13; - else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) villagerIndex = 12; else villagerIndex = 16; register(new VillagerTypeProperty("villager_type", villagerIndex, VillagerType.PLAINS)); register(new VillagerProfessionProperty("villager_profession", villagerIndex, VillagerProfession.NONE)); From 8e1e0c818feec45649b0625affb37dbbaa8f0875 Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Wed, 1 May 2024 19:19:29 +0530 Subject: [PATCH 7/9] fix client side desync when interacting with allays --- .../java/lol/pyr/znpcsplus/ZNpcsPlus.java | 2 +- .../InteractionPacketListener.java | 27 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java index fd95cd0..52abae7 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java @@ -138,7 +138,7 @@ public class ZNpcsPlus { typeRegistry.registerDefault(packetEvents, propertyRegistry); actionRegistry.registerTypes(scheduler, adventure, textSerializer, bungeeConnector); - packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, scheduler), PacketListenerPriority.MONITOR); + packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, typeRegistry, scheduler), PacketListenerPriority.MONITOR); new Metrics(bootstrap, 18244); pluginManager.registerEvents(new UserListener(userManager), bootstrap); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/interaction/InteractionPacketListener.java b/plugin/src/main/java/lol/pyr/znpcsplus/interaction/InteractionPacketListener.java index c27f3b6..8734c0e 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/interaction/InteractionPacketListener.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/interaction/InteractionPacketListener.java @@ -1,29 +1,39 @@ package lol.pyr.znpcsplus.interaction; +import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.PacketListener; import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.protocol.item.ItemStack; import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.protocol.player.Equipment; +import com.github.retrooper.packetevents.protocol.player.EquipmentSlot; import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment; import lol.pyr.znpcsplus.api.event.NpcInteractEvent; import lol.pyr.znpcsplus.api.interaction.InteractionAction; import lol.pyr.znpcsplus.api.interaction.InteractionType; import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl; +import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.user.User; import lol.pyr.znpcsplus.user.UserManager; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import java.util.Collections; + public class InteractionPacketListener implements PacketListener { private final UserManager userManager; private final NpcRegistryImpl npcRegistry; + private final NpcTypeRegistryImpl typeRegistry; private final TaskScheduler scheduler; - public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry, TaskScheduler scheduler) { + public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, TaskScheduler scheduler) { this.userManager = userManager; this.npcRegistry = npcRegistry; + this.typeRegistry = typeRegistry; this.scheduler = scheduler; } @@ -34,14 +44,25 @@ public class InteractionPacketListener implements PacketListener { if (player == null) return; WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event); - User user = userManager.get(player); - if (!user.canInteract()) return; NpcEntryImpl entry = npcRegistry.getByEntityId(packet.getEntityId()); if (entry == null || !entry.isProcessed()) return; NpcImpl npc = entry.getNpc(); + + if ((packet.getAction().equals(WrapperPlayClientInteractEntity.InteractAction.INTERACT) + || packet.getAction().equals(WrapperPlayClientInteractEntity.InteractAction.INTERACT_AT)) + && npc.getType().equals(typeRegistry.getByName("allay"))) { + PacketEvents.getAPI().getPlayerManager().sendPacket(player, + new WrapperPlayServerEntityEquipment(packet.getEntityId(), Collections.singletonList( + new Equipment(EquipmentSlot.MAIN_HAND, ItemStack.EMPTY)))); + player.updateInventory(); + } + InteractionType type = wrapClickType(packet.getAction()); + User user = userManager.get(player); + if (!user.canInteract()) return; + NpcInteractEvent interactEvent = new NpcInteractEvent(player, entry, type); Bukkit.getPluginManager().callEvent(interactEvent); if (interactEvent.isCancelled()) return; From 0d58cdc20b1f62445e987a43686f7e83f957e2c5 Mon Sep 17 00:00:00 2001 From: D3v1s0m Date: Wed, 1 May 2024 21:29:34 +0530 Subject: [PATCH 8/9] added player knockback properties --- .../java/lol/pyr/znpcsplus/ZNpcsPlus.java | 3 +- .../entity/EntityPropertyRegistryImpl.java | 16 +++++ .../lol/pyr/znpcsplus/npc/NpcTypeImpl.java | 5 +- .../pyr/znpcsplus/tasks/NpcProcessorTask.java | 58 ++++++++++++++++++- .../java/lol/pyr/znpcsplus/user/User.java | 9 +++ 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java index 52abae7..5829d99 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java @@ -152,7 +152,7 @@ public class ZNpcsPlus { pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker, scheduler), bootstrap); } - scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, propertyRegistry), 60L, 3L); + scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, propertyRegistry, userManager), 60L, 3L); scheduler.runDelayedTimerAsync(new HologramRefreshTask(npcRegistry), 60L, 20L); scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200); pluginManager.registerEvents(new ViewableHideOnLeaveListener(), bootstrap); @@ -275,6 +275,7 @@ public class ZNpcsPlus { registerEnumParser(manager, SnifferState.class, incorrectUsageMessage); registerEnumParser(manager, RabbitType.class, incorrectUsageMessage); registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage); + registerEnumParser(manager, Sound.class, incorrectUsageMessage); manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root")) .addSubcommand("center", new CenterCommand(npcRegistry)) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java index adf1b35..64b43a5 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/entity/EntityPropertyRegistryImpl.java @@ -24,6 +24,7 @@ import lol.pyr.znpcsplus.util.*; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Color; import org.bukkit.DyeColor; +import org.bukkit.Sound; import java.util.*; import java.util.stream.Collectors; @@ -84,6 +85,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { registerEnumSerializer(SnifferState.class); registerEnumSerializer(RabbitType.class); registerEnumSerializer(AttachDirection.class); + registerEnumSerializer(Sound.class); registerPrimitiveSerializers(Integer.class, Boolean.class, Double.class, Float.class, Long.class, Short.class, Byte.class, String.class); @@ -122,6 +124,20 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry { register(new DummyProperty<>("permission_required", false)); + register(new DummyProperty<>("player_knockback", false)); + register(new DummyProperty<>("player_knockback_exempt_permission", String.class)); + register(new DummyProperty<>("player_knockback_distance", 0.4)); + register(new DummyProperty<>("player_knockback_vertical", 0.4)); + register(new DummyProperty<>("player_knockback_horizontal", 0.9)); + register(new DummyProperty<>("player_knockback_cooldown", 1500)); + register(new DummyProperty<>("player_knockback_sound", false)); + register(new DummyProperty<>("player_knockback_sound_volume", 1.0f)); + register(new DummyProperty<>("player_knockback_sound_pitch", 1.0f)); + register(new DummyProperty<>("player_knockback_sound_name", Sound.valueOf( + PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9) ? + "VILLAGER_NO" : "ENTITY_VILLAGER_NO" + ))); + register(new GlowProperty(packetFactory)); register(new BitsetProperty("fire", 0, 0x01)); register(new BitsetProperty("invisible", 0, 0x20)); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java index 3e5119d..565493f 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java @@ -115,7 +115,10 @@ public class NpcTypeImpl implements NpcType { public NpcTypeImpl build() { ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion(); addProperties("fire", "invisible", "silent", "look", "look_distance", "view_distance", - "potion_color", "potion_ambient", "display_name", "permission_required"); + "potion_color", "potion_ambient", "display_name", "permission_required", + "player_knockback", "player_knockback_exempt_permission", "player_knockback_distance", "player_knockback_vertical", + "player_knockback_horizontal", "player_knockback_cooldown", "player_knockback_sound", "player_knockback_sound_name", + "player_knockback_sound_volume", "player_knockback_sound_pitch"); if (!type.equals(EntityTypes.PLAYER)) addProperties("dinnerbone"); // TODO: make this look nicer after completing the rest of the properties if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow"); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java b/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java index f92838d..e0cdcf1 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java @@ -7,20 +7,26 @@ import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; import lol.pyr.znpcsplus.npc.NpcEntryImpl; import lol.pyr.znpcsplus.npc.NpcImpl; import lol.pyr.znpcsplus.npc.NpcRegistryImpl; +import lol.pyr.znpcsplus.user.User; +import lol.pyr.znpcsplus.user.UserManager; import lol.pyr.znpcsplus.util.LookType; import lol.pyr.znpcsplus.util.NpcLocation; import org.bukkit.Bukkit; +import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.NumberConversions; +import org.bukkit.util.Vector; public class NpcProcessorTask extends BukkitRunnable { private final NpcRegistryImpl npcRegistry; private final EntityPropertyRegistryImpl propertyRegistry; + private final UserManager userManager; - public NpcProcessorTask(NpcRegistryImpl npcRegistry, EntityPropertyRegistryImpl propertyRegistry) { + public NpcProcessorTask(NpcRegistryImpl npcRegistry, EntityPropertyRegistryImpl propertyRegistry,UserManager userManager) { this.npcRegistry = npcRegistry; this.propertyRegistry = propertyRegistry; + this.userManager = userManager; } public void run() { @@ -28,7 +34,28 @@ public class NpcProcessorTask extends BukkitRunnable { EntityPropertyImpl lookProperty = propertyRegistry.getByName("look", LookType.class); EntityPropertyImpl lookDistanceProperty = propertyRegistry.getByName("look_distance", Double.class); EntityPropertyImpl permissionRequiredProperty = propertyRegistry.getByName("permission_required", Boolean.class); + EntityPropertyImpl playerKnockbackProperty = propertyRegistry.getByName("player_knockback", Boolean.class); + EntityPropertyImpl playerKnockbackExemptPermissionProperty = propertyRegistry.getByName("player_knockback_exempt_permission", String.class); + EntityPropertyImpl playerKnockbackDistanceProperty = propertyRegistry.getByName("player_knockback_distance", Double.class); + EntityPropertyImpl playerKnockbackVerticalProperty = propertyRegistry.getByName("player_knockback_vertical", Double.class); + EntityPropertyImpl playerKnockbackHorizontalProperty = propertyRegistry.getByName("player_knockback_horizontal", Double.class); + EntityPropertyImpl playerKnockbackCooldownProperty = propertyRegistry.getByName("player_knockback_cooldown", Integer.class); + EntityPropertyImpl playerKnockbackSoundProperty = propertyRegistry.getByName("player_knockback_sound", Boolean.class); + EntityPropertyImpl playerKnockbackSoundNameProperty = propertyRegistry.getByName("player_knockback_sound_name", Sound.class); + EntityPropertyImpl playerKnockbackSoundVolumeProperty = propertyRegistry.getByName("player_knockback_sound_volume", Float.class); + EntityPropertyImpl playerKnockbackSoundPitchProperty = propertyRegistry.getByName("player_knockback_sound_pitch", Float.class); double lookDistance; + boolean permissionRequired; + boolean playerKnockback; + String playerKnockbackExemptPermission = null; + double playerKnockbackDistance = 0; + double playerKnockbackVertical = 0; + double playerKnockbackHorizontal = 0; + int playerKnockbackCooldown = 0; + boolean playerKnockbackSound = false; + Sound playerKnockbackSoundName = null; + float playerKnockbackSoundVolume = 0; + float playerKnockbackSoundPitch = 0; for (NpcEntryImpl entry : npcRegistry.getProcessable()) { NpcImpl npc = entry.getNpc(); if (!npc.isEnabled()) continue; @@ -37,7 +64,19 @@ public class NpcProcessorTask extends BukkitRunnable { Player closest = null; LookType lookType = npc.getProperty(lookProperty); lookDistance = NumberConversions.square(npc.getProperty(lookDistanceProperty)); - boolean permissionRequired = npc.getProperty(permissionRequiredProperty); + permissionRequired = npc.getProperty(permissionRequiredProperty); + playerKnockback = npc.getProperty(playerKnockbackProperty); + if (playerKnockback) { + playerKnockbackExemptPermission = npc.getProperty(playerKnockbackExemptPermissionProperty); + playerKnockbackDistance = NumberConversions.square(npc.getProperty(playerKnockbackDistanceProperty)); + playerKnockbackVertical = npc.getProperty(playerKnockbackVerticalProperty); + playerKnockbackHorizontal = npc.getProperty(playerKnockbackHorizontalProperty); + playerKnockbackCooldown = npc.getProperty(playerKnockbackCooldownProperty); + playerKnockbackSound = npc.getProperty(playerKnockbackSoundProperty); + playerKnockbackSoundName = npc.getProperty(playerKnockbackSoundNameProperty); + playerKnockbackSoundVolume = npc.getProperty(playerKnockbackSoundVolumeProperty); + playerKnockbackSoundPitch = npc.getProperty(playerKnockbackSoundPitchProperty); + } for (Player player : Bukkit.getOnlinePlayers()) { if (!player.getWorld().equals(npc.getWorld())) { if (npc.isVisibleTo(player)) npc.hide(player); @@ -71,6 +110,21 @@ public class NpcProcessorTask extends BukkitRunnable { NpcLocation expected = npc.getLocation().lookingAt(player.getLocation().add(0, -npc.getType().getHologramOffset(), 0)); if (!expected.equals(npc.getLocation())) npc.setHeadRotation(player, expected.getYaw(), expected.getPitch()); } + + // player knockback + User user = userManager.get(player.getUniqueId()); + if (playerKnockbackExemptPermission == null || !player.hasPermission(playerKnockbackExemptPermission)) { + if (playerKnockback && distance <= playerKnockbackDistance && user.canKnockback(playerKnockbackCooldown)) { + double x = npc.getLocation().getX() - player.getLocation().getX(); + double z = npc.getLocation().getZ() - player.getLocation().getZ(); + double angle = Math.atan2(z, x); + double knockbackX = -Math.cos(angle) * playerKnockbackHorizontal; + double knockbackZ = -Math.sin(angle) * playerKnockbackHorizontal; + player.setVelocity(player.getVelocity().add(new Vector(knockbackX, playerKnockbackVertical, knockbackZ))); + if (playerKnockbackSound) + player.playSound(player.getLocation(), playerKnockbackSoundName, playerKnockbackSoundVolume, playerKnockbackSoundPitch); + } + } } } // look property diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/user/User.java b/plugin/src/main/java/lol/pyr/znpcsplus/user/User.java index 2d9e45f..216001e 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/user/User.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/user/User.java @@ -11,6 +11,7 @@ import java.util.UUID; public class User { private final UUID uuid; private long lastNpcInteraction; + private long lastNpcKnockback; private final Map actionCooldownMap = new HashMap<>(); public User(UUID uuid) { @@ -29,6 +30,14 @@ public class User { return false; } + public boolean canKnockback(int cooldown) { + if (System.currentTimeMillis() - lastNpcKnockback > cooldown) { + lastNpcKnockback = System.currentTimeMillis(); + return true; + } + return false; + } + public UUID getUuid() { return uuid; } From 36a656ca3054d1ecc31895afa39afeb653feaf69 Mon Sep 17 00:00:00 2001 From: Pyrbu Date: Fri, 10 May 2024 17:15:24 +0200 Subject: [PATCH 9/9] update packetevents --- plugin/build.gradle | 2 +- .../src/main/java/lol/pyr/znpcsplus/ZNpcsPlusBootstrap.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/build.gradle b/plugin/build.gradle index 5d7db1b..3364faf 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -20,7 +20,7 @@ dependencies { compileOnly "com.google.code.gson:gson:2.10.1" // JSON parsing compileOnly "org.bstats:bstats-bukkit:3.0.2" // Plugin stats compileOnly "me.robertlit:SpigotResourcesAPI:2.0" // Spigot API wrapper for update checker - compileOnly "com.github.retrooper.packetevents:spigot:2.2.1" // Packets + compileOnly "com.github.retrooper.packetevents:spigot:2.3.0" // Packets compileOnly "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1" // Configs compileOnly "lol.pyr:director-adventure:2.1.1" // Commands diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusBootstrap.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusBootstrap.java index 1dadd3e..c18c741 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusBootstrap.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusBootstrap.java @@ -45,7 +45,7 @@ public class ZNpcsPlusBootstrap extends JavaPlugin { loader.addRelocation(decrypt("org..yaml..snakeyaml"), "lol.pyr.znpcsplus.libraries.snakeyaml"); loader.addRelocation(decrypt("space..arim..dazzleconf"), "lol.pyr.znpcsplus.libraries.dazzleconf"); loader.addRelocation(decrypt("lol..pyr..director"), "lol.pyr.znpcsplus.libraries.command"); - + loader.loadLibrary(decrypt("com..google..guava"), "guava", "18.0"); loader.loadLibrary(decrypt("com..google..code..gson"), "gson", "2.10.1"); @@ -54,8 +54,8 @@ public class ZNpcsPlusBootstrap extends JavaPlugin { loader.loadLibrary("me.robertlit", "SpigotResourcesAPI", "2.0", "https://repo.pyr.lol/releases"); - loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "api", "2.2.1", "https://repo.codemc.io/repository/maven-releases/"); - loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "spigot", "2.2.1", "https://repo.codemc.io/repository/maven-releases/"); + loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "api", "2.3.0", "https://repo.codemc.io/repository/maven-releases/"); + loader.loadLibrary(decrypt("com..github..retrooper..packetevents"), "spigot", "2.3.0", "https://repo.codemc.io/repository/maven-releases/"); loader.loadLibrary(decrypt("space..arim..dazzleconf"), "dazzleconf-core", "1.2.1"); loader.loadLibrary(decrypt("space..arim..dazzleconf"), "dazzleconf-ext-snakeyaml", "1.2.1");