diff --git a/.gitignore b/.gitignore index b63da45..e21d8b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ build/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ +run/ ### IntelliJ IDEA ### .idea/modules.xml diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 2c99fbb..12993cb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,9 +2,9 @@ import java.io.BufferedReader import java.io.InputStreamReader plugins { + id("java") alias(libs.plugins.runPaper) alias(libs.plugins.paperweight) apply true - alias(libs.plugins.kotlinJvm) apply true alias(libs.plugins.shadow) apply true `maven-publish` @@ -23,13 +23,16 @@ repositories { maven("https://repo.dmulloy2.net/repository/public/") maven("https://jitpack.io") maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") + maven("https://repo.codemc.io/repository/maven-releases/") + maven("https://maven.evokegames.gg/snapshots") } dependencies { paperweight.paperDevBundle(libs.versions.paperApi.get()) - compileOnly(libs.ktgui) compileOnly(libs.placeholder.api) + compileOnly(libs.packet.events) + implementation(libs.entity.lib) } tasks { @@ -82,9 +85,9 @@ java { withSourcesJar() } -kotlin { - jvmToolchain(17) -} +//kotlin { +// jvmToolchain(21) +//} sourceSets["main"].resources.srcDir("src/resources/") diff --git a/gradle.properties b/gradle.properties index 7dbbec3..61e8bd5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,11 +2,11 @@ kotlin.code.style=official # Project configuration group_name = com.mattmx -id = template +id = nametags version = 1.0 -plugin_name = Template -plugin_main_class_name = TemplatePlugin +plugin_name = NameTags +plugin_main_class_name = NameTags plugin_author = MattMX include_commit_hash = true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9717558..15f0209 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,9 @@ placeholderapi = "2.11.6" ktgui = "2.4.2-alpha" runPaper = "2.2.4" +packetEvents = "2.4.0" +entityLib = "2.4.9-SNAPSHOT" + [libraries] kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } @@ -16,6 +19,8 @@ kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = " paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paperApi" } placeholder-api = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } ktgui = { module = "com.mattmx:ktgui", version.ref = "ktgui" } +packet-events = { module = "com.github.retrooper:packetevents-spigot", version.ref = "packetEvents" } +entity-lib = { module = "me.tofaa.entitylib:spigot", version.ref = "entityLib" } [plugins] diff --git a/run/plugins/packetevents-spigot-2.4.0 (3).jar b/run/plugins/packetevents-spigot-2.4.0 (3).jar new file mode 100644 index 0000000..682254f Binary files /dev/null and b/run/plugins/packetevents-spigot-2.4.0 (3).jar differ diff --git a/src/main/java/com/mattmx/nametags/EventsListener.java b/src/main/java/com/mattmx/nametags/EventsListener.java new file mode 100644 index 0000000..9f7de87 --- /dev/null +++ b/src/main/java/com/mattmx/nametags/EventsListener.java @@ -0,0 +1,45 @@ +package com.mattmx.nametags; + +import com.github.retrooper.packetevents.protocol.world.Location; +import com.mattmx.nametags.entity.NameTagEntity; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.jetbrains.annotations.NotNull; + +public class EventsListener implements Listener { + + @EventHandler + public void onPlayerJoin(@NotNull PlayerJoinEvent event) { + NameTagEntity nameTagEntity = NameTags.getInstance() + .getEntityManager() + .getOrCreateNameTagEntity(event.getPlayer()); + } + + @EventHandler + public void onPlayerQuit(@NotNull PlayerQuitEvent event) { + NameTagEntity entity = NameTags.getInstance() + .getEntityManager() + .removeEntity(event.getPlayer()); + + if (entity == null) return; + + entity.getPassenger().despawn(); + } + + @EventHandler + public void onChangeWorld(@NotNull PlayerChangedWorldEvent event) { + NameTagEntity nameTagEntity = NameTags.getInstance() + .getEntityManager() + .getNameTagEntity(event.getPlayer()); + + if (nameTagEntity == null) return; + + Location newLocation = SpigotConversionUtil.fromBukkitLocation(event.getPlayer().getLocation()); + + nameTagEntity.getPassenger().setLocation(newLocation); + } +} diff --git a/src/main/java/com/mattmx/nametags/NameTags.java b/src/main/java/com/mattmx/nametags/NameTags.java new file mode 100644 index 0000000..f1deb5b --- /dev/null +++ b/src/main/java/com/mattmx/nametags/NameTags.java @@ -0,0 +1,51 @@ +package com.mattmx.nametags; + +import com.github.retrooper.packetevents.PacketEvents; +import com.mattmx.nametags.entity.NameTagEntityManager; +import me.tofaa.entitylib.APIConfig; +import me.tofaa.entitylib.EntityLib; +import me.tofaa.entitylib.spigot.SpigotEntityLibPlatform; +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NameTags extends JavaPlugin { + private static @Nullable NameTags instance; + + private NameTagEntityManager entityManager; + private final EventsListener eventsListener = new EventsListener(); + private final OutgoingPacketListener packetListener = new OutgoingPacketListener(this); + + @Override + public void onEnable() { + instance = this; + entityManager = new NameTagEntityManager(); + + SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(this); + APIConfig settings = new APIConfig(PacketEvents.getAPI()) + .debugMode() + .tickTickables() + .trackPlatformEntities() + .usePlatformLogger(); + + EntityLib.init(platform, settings); + + PacketEvents.getAPI() + .getEventManager() + .registerListener(packetListener); + + Bukkit.getPluginManager().registerEvents(eventsListener, this); + } + + public @NotNull NameTagEntityManager getEntityManager() { + return this.entityManager; + } + + public static @NotNull NameTags getInstance() { + if (instance == null) + throw new RuntimeException("NameTags plugin has not initialized yet! Did you forget to depend?"); + + return instance; + } +} diff --git a/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java b/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java new file mode 100644 index 0000000..6d13965 --- /dev/null +++ b/src/main/java/com/mattmx/nametags/OutgoingPacketListener.java @@ -0,0 +1,53 @@ +package com.mattmx.nametags; + +import com.github.retrooper.packetevents.event.PacketListenerAbstract; +import com.github.retrooper.packetevents.event.PacketSendEvent; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity; +import com.mattmx.nametags.entity.NameTagEntity; +import org.jetbrains.annotations.NotNull; + +public class OutgoingPacketListener extends PacketListenerAbstract { + + private NameTags plugin; + + public OutgoingPacketListener(NameTags plugin) { + this.plugin = plugin; + } + + @Override + public void onPacketSend(@NotNull PacketSendEvent event) { + switch (event.getPacketType()) { + case PacketType.Play.Server.SPAWN_ENTITY -> { + WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(event); + + if (packet.getUUID().isEmpty()) return; + + NameTagEntity nameTagEntity = plugin.getEntityManager().getNameTagEntityByUUID(packet.getUUID().get()); + + if (nameTagEntity == null) return; + + // Add passenger and send to player (Delayed so this packet sends first) + event.getTasksAfterSend().add(() -> { + nameTagEntity.getPassenger().removeViewer(event.getUser()); + nameTagEntity.getPassenger().addViewer(event.getUser()); + event.getUser().sendPacket(nameTagEntity.getPassengersPacket()); + }); + } + case PacketType.Play.Server.DESTROY_ENTITIES -> { + WrapperPlayServerDestroyEntities packet = new WrapperPlayServerDestroyEntities(event); + + for (int entityId : packet.getEntityIds()) { + NameTagEntity nameTagEntity = plugin.getEntityManager().getNameTagEntityById(entityId); + + if (nameTagEntity == null) continue; + + nameTagEntity.getPassenger().removeViewer(event.getUser()); + } + } + default -> { + } + } + } +} diff --git a/src/main/java/com/mattmx/nametags/entity/NameTagEntity.java b/src/main/java/com/mattmx/nametags/entity/NameTagEntity.java new file mode 100644 index 0000000..f4a76a9 --- /dev/null +++ b/src/main/java/com/mattmx/nametags/entity/NameTagEntity.java @@ -0,0 +1,60 @@ +package com.mattmx.nametags.entity; + +import com.github.retrooper.packetevents.PacketEvents; +import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes; +import com.github.retrooper.packetevents.util.Vector3f; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers; +import io.github.retrooper.packetevents.util.SpigotConversionUtil; +import me.tofaa.entitylib.meta.display.AbstractDisplayMeta; +import me.tofaa.entitylib.meta.display.TextDisplayMeta; +import me.tofaa.entitylib.wrapper.WrapperEntity; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Color; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class NameTagEntity { + private final @NotNull Entity bukkitEntity; + private final @NotNull WrapperEntity passenger; + + public NameTagEntity(@NotNull Entity entity) { + this.bukkitEntity = entity; + this.passenger = new WrapperEntity(EntityTypes.TEXT_DISPLAY); + + applyDefaultMeta(); + } + + public void applyDefaultMeta() { + this.passenger.consumeEntityMeta(TextDisplayMeta.class, (meta) -> { + meta.setText(bukkitEntity.name()); + meta.setTranslation(new Vector3f(0f, 0.25f, 0f)); + meta.setBackgroundColor(Color.RED.setAlpha(50).asARGB()); + meta.setBillboardConstraints(AbstractDisplayMeta.BillboardConstraints.CENTER); + }); + + this.passenger.spawn(SpigotConversionUtil.fromBukkitLocation(this.bukkitEntity.getLocation())); + + // TODO: Send packet to player if enabled in config + } + + public void sendPassengerPacket(Player target) { + PacketEvents.getAPI() + .getPlayerManager() + .sendPacket(target, getPassengersPacket()); + } + + public PacketWrapper getPassengersPacket() { + return new WrapperPlayServerSetPassengers(bukkitEntity.getEntityId(), new int[]{this.passenger.getEntityId()}); + } + + public Entity getBukkitEntity() { + return bukkitEntity; + } + + public WrapperEntity getPassenger() { + return passenger; + } +} diff --git a/src/main/java/com/mattmx/nametags/entity/NameTagEntityManager.java b/src/main/java/com/mattmx/nametags/entity/NameTagEntityManager.java new file mode 100644 index 0000000..0100e5a --- /dev/null +++ b/src/main/java/com/mattmx/nametags/entity/NameTagEntityManager.java @@ -0,0 +1,36 @@ +package com.mattmx.nametags.entity; + +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class NameTagEntityManager { + private final ConcurrentHashMap entityMap = new ConcurrentHashMap<>(); + + public @NotNull NameTagEntity getOrCreateNameTagEntity(@NotNull Entity entity) { + return entityMap.computeIfAbsent(entity.getUniqueId(), (k) -> new NameTagEntity(entity)); + } + + public @Nullable NameTagEntity removeEntity(@NotNull Entity entity) { + return entityMap.remove(entity.getUniqueId()); + } + + public @Nullable NameTagEntity getNameTagEntity(@NotNull Entity entity) { + return entityMap.get(entity.getUniqueId()); + } + + public @Nullable NameTagEntity getNameTagEntityByUUID(UUID uuid) { + return entityMap.get(uuid); + } + + public @Nullable NameTagEntity getNameTagEntityById(int entityId) { + return entityMap.values() + .stream() + .filter((e) -> e.getBukkitEntity().getEntityId() == entityId) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/kotlin/com/mattmx/template/TemplatePlugin.kt b/src/main/kotlin/com/mattmx/template/TemplatePlugin.kt deleted file mode 100644 index dc603ac..0000000 --- a/src/main/kotlin/com/mattmx/template/TemplatePlugin.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.mattmx.template - -import com.mattmx.ktgui.GuiManager -import org.bukkit.plugin.java.JavaPlugin - -class TemplatePlugin : JavaPlugin() { - - override fun onEnable() { - instance = this - GuiManager.init(this) - } - - companion object { - private lateinit var instance: TemplatePlugin - fun get() = instance - } - -} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 1932adb..3cb945b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,9 +4,8 @@ version: ${version} author: ${author} api-version: 1.17 -softdepend: - - PlaceholderAPI - - MCKotlin-Paper +depend: + - packetevents -libraries: - - org.jetbrains.kotlin:kotlin-stdlib:2.0.0 \ No newline at end of file +softdepend: + - PlaceholderAPI \ No newline at end of file