From ad82d280b655136d2857b59d35a0d2abb4a87101 Mon Sep 17 00:00:00 2001 From: Ashijin <xikage@gmail.com> Date: Sat, 7 Jan 2023 16:56:00 -0700 Subject: [PATCH] 1.19.3 support, cleaned up dependencies --- api/.flattened-pom.xml | 12 +- dist/pom.xml | 6 + plugin/pom.xml | 16 +- .../cosmetics/menus/SelectColorContext.java | 17 + .../cosmetics/menus/SelectColorMenu.java | 35 ++ plugin/src/main/resources-filtered/plugin.yml | 2 +- pom.xml | 15 +- sql/pom.xml | 14 +- v1_17_R1/pom.xml | 20 +- v1_18_R1/pom.xml | 20 +- v1_18_R2/pom.xml | 14 +- v1_19_R1/pom.xml | 14 +- v1_19_R1_2/pom.xml | 14 +- v1_19_R2/.gitignore | 1 + v1_19_R2/pom.xml | 164 ++++++++++ .../nms/VolatileCodeEnabled_v1_19_R2.java | 184 +++++++++++ .../v1_19_R2/cosmetic/VolatileBackImpl.java | 305 ++++++++++++++++++ .../cosmetic/VolatileGestureImpl.java | 178 ++++++++++ .../v1_19_R2/cosmetic/VolatileHatImpl.java | 199 ++++++++++++ .../cosmetic/VolatileOffhandImpl.java | 173 ++++++++++ .../v1_19_R2/cosmetic/VolatileSprayImpl.java | 90 ++++++ .../network/VolatileChannelHandler.java | 61 ++++ .../v1_19_R2/wardrobe/MannequinEntity.java | 132 ++++++++ 23 files changed, 1573 insertions(+), 113 deletions(-) create mode 100644 plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorContext.java create mode 100644 plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorMenu.java create mode 100644 v1_19_R2/.gitignore create mode 100644 v1_19_R2/pom.xml create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/VolatileCodeEnabled_v1_19_R2.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileBackImpl.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileGestureImpl.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileHatImpl.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileOffhandImpl.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileSprayImpl.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/network/VolatileChannelHandler.java create mode 100644 v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/wardrobe/MannequinEntity.java diff --git a/api/.flattened-pom.xml b/api/.flattened-pom.xml index d5b6fab..5e652fa 100644 --- a/api/.flattened-pom.xml +++ b/api/.flattened-pom.xml @@ -4,12 +4,12 @@ <modelVersion>4.0.0</modelVersion> <groupId>io.lumine</groupId> <artifactId>MCCosmetics-API</artifactId> - <version>0.8.0-SNAPSHOT</version> + <version>0.11.0</version> <dependencies> <dependency> <groupId>io.lumine</groupId> <artifactId>LumineUtils</artifactId> - <version>1.18-SNAPSHOT</version> + <version>1.19-SNAPSHOT</version> <scope>provided</scope> </dependency> <dependency> @@ -38,10 +38,6 @@ <id>lumine</id> <url>https://mvn.lumine.io/repository/maven/</url> </repository> - <repository> - <id>sk89q-repo</id> - <url>https://maven.sk89q.com/repo/</url> - </repository> <repository> <id>md_5-snapshots</id> <url>https://repo.md-5.net/content/repositories/snapshots/</url> @@ -50,10 +46,6 @@ <id>placeholderapi</id> <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> </repository> - <repository> - <id>filoghost-repo</id> - <url>https://ci.filoghost.me/plugin/repository/everything/</url> - </repository> <repository> <id>papermc</id> <url>https://papermc.io/repo/repository/maven-public/</url> diff --git a/dist/pom.xml b/dist/pom.xml index b935380..17ee340 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -64,6 +64,12 @@ <version>${project.parent.version}</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>io.lumine</groupId> + <artifactId>MCCosmetics-v1_19_R2</artifactId> + <version>${project.parent.version}</version> + <scope>compile</scope> + </dependency> </dependencies> <build> diff --git a/plugin/pom.xml b/plugin/pom.xml index b2d2bc6..e6e2853 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -82,13 +82,9 @@ </build> <repositories> <repository> - <id>nexus</id> + <id>lumine</id> <url>https://mvn.lumine.io/repository/maven/</url> </repository> - <repository> - <id>lumine-public</id> - <url>https://mvn.lumine.io/repository/maven-public/</url> - </repository> <repository> <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/groups/public/</url> @@ -113,10 +109,6 @@ <updatePolicy>never</updatePolicy> </releases> </repository> --> - <repository> - <id>sk89q-repo</id> - <url>https://maven.sk89q.com/repo/</url> - </repository> <repository> <id>md_5-public</id> <url>https://repo.md-5.net/content/groups/public/</url> @@ -129,10 +121,6 @@ <id>placeholderapi</id> <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> </repository> - <repository> - <id>filoghost-repo</id> - <url>https://ci.filoghost.me/plugin/repository/everything/</url> - </repository> <repository> <id>CodeMC</id> <url>https://repo.codemc.org/repository/maven-public</url> @@ -187,7 +175,7 @@ <dependency> <groupId>com.ticxo.playeranimator</groupId> <artifactId>PlayerAnimator</artifactId> - <version>R1.2.4</version> + <version>R1.2.5</version> </dependency> <!-- Spigot API --> diff --git a/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorContext.java b/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorContext.java new file mode 100644 index 0000000..27067c6 --- /dev/null +++ b/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorContext.java @@ -0,0 +1,17 @@ +package io.lumine.cosmetics.menus; + +import io.lumine.cosmetics.api.cosmetics.Cosmetic; +import io.lumine.cosmetics.managers.MCCosmeticsManager; +import io.lumine.cosmetics.players.Profile; +import io.lumine.utils.serialize.Chroma; +import lombok.Data; + +@Data +public class SelectColorContext { + + private final Profile profile; + private final MCCosmeticsManager manager; + private final Cosmetic cosmetic; + private Chroma chroma; + +} diff --git a/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorMenu.java b/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorMenu.java new file mode 100644 index 0000000..5bdc13e --- /dev/null +++ b/plugin/src/main/java/io/lumine/cosmetics/menus/SelectColorMenu.java @@ -0,0 +1,35 @@ +package io.lumine.cosmetics.menus; + +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.players.Profile; +import io.lumine.utils.config.properties.types.MenuProp; +import io.lumine.utils.menu.EditableMenuBuilder; +import io.lumine.utils.menu.Icon; +import io.lumine.utils.menu.MenuData; + +public class SelectColorMenu extends CosmeticMenu<SelectColorContext> { + + public SelectColorMenu(MCCosmeticsPlugin core, MenuManager manager, String type) { + super(core, manager, new MenuProp(core, "menus/color_picker", "Menu", null)); + } + + @Override + public EditableMenuBuilder<SelectColorContext> build(EditableMenuBuilder<SelectColorContext> builder) { + + + return builder; + } + + public static class ColorSwatch implements MenuData<SelectColorContext> { + + + + @Override + public Icon<SelectColorContext> getIcon() { + // TODO Auto-generated method stub + return null; + } + + } + +} diff --git a/plugin/src/main/resources-filtered/plugin.yml b/plugin/src/main/resources-filtered/plugin.yml index 4a81064..d5b999a 100644 --- a/plugin/src/main/resources-filtered/plugin.yml +++ b/plugin/src/main/resources-filtered/plugin.yml @@ -12,7 +12,7 @@ softdepend: - PlaceholderAPI - WorldGuard loadbefore: [] -description: The total solution for all things mob-related. +description: Plugin for adding amazing cosmetics, brought to you by MCModels commands: mccosmetics: description: MCCosmetics admin command diff --git a/pom.xml b/pom.xml index 24e5a13..ff8d586 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ </organization> <properties> - <mccosmetics.version>0.10.0</mccosmetics.version> + <mccosmetics.version>0.11.0</mccosmetics.version> <paperapi.version>1.19-R0.1-SNAPSHOT</paperapi.version> <lumineutils.version>1.19-SNAPSHOT</lumineutils.version> <lombok.version>1.18.22</lombok.version> @@ -36,6 +36,7 @@ <module>v1_18_R2</module> <module>v1_19_R1</module> <module>v1_19_R1_2</module> + <module>v1_19_R2</module> <module>dist</module> <module>dist-premium</module> </modules> @@ -91,10 +92,6 @@ <id>lumine</id> <url>https://mvn.lumine.io/repository/maven/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> <!-- <repository> <id>bstats-repo</id> <url>http://repo.bstats.org/content/repositories/releases/</url> @@ -107,10 +104,6 @@ <updatePolicy>never</updatePolicy> </releases> </repository> --> - <repository> - <id>sk89q-repo</id> - <url>https://maven.sk89q.com/repo/</url> - </repository> <repository> <id>md_5-snapshots</id> <url>https://repo.md-5.net/content/repositories/snapshots/</url> @@ -119,10 +112,6 @@ <id>placeholderapi</id> <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> </repository> - <repository> - <id>filoghost-repo</id> - <url>https://ci.filoghost.me/plugin/repository/everything/</url> - </repository> <repository> <id>papermc</id> <url>https://papermc.io/repo/repository/maven-public/</url> diff --git a/sql/pom.xml b/sql/pom.xml index 7df4e48..884c500 100644 --- a/sql/pom.xml +++ b/sql/pom.xml @@ -2,7 +2,7 @@ <modelVersion>4.0.0</modelVersion> <artifactId>MCCosmetics-SQL</artifactId> - <parent> + <parent> <groupId>io.lumine</groupId> <artifactId>MCCosmetics-Plugin</artifactId> <version>${mccosmetics.version}</version> @@ -16,6 +16,12 @@ </pluginRepositories> <dependencies> + <dependency> + <groupId>io.lumine</groupId> + <artifactId>MCCosmetics-API</artifactId> + <version>${mccosmetics.version}</version> + <scope>provided</scope> + </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> @@ -90,7 +96,7 @@ <jdbc> <driver>org.mariadb.jdbc.Driver</driver> - <url>jdbc:mariadb://localhost:3306/mythiccraft_test_mccosmetics</url> + <url>jdbc:mariadb://localhost:3306/mythiccraft_test_achievements</url> <user>mythiccraft_tester</user> <password>62e06d5e-6c48-4c40-a070-00949d2a9c6a</password> </jdbc> @@ -102,13 +108,13 @@ <excludes></excludes> <schemata> <schema> - <inputSchema>mythiccraft_test_mccosmetics</inputSchema> + <inputSchema>mythiccraft_test_achievements</inputSchema> <outputSchemaToDefault>true</outputSchemaToDefault> </schema> </schemata> </database> <target> - <packageName>io.lumine.cosmetics.storage.sql.mappings</packageName> + <packageName>io.lumine.achievements.storage.sql.jooq</packageName> <directory>../plugin/src/main/java</directory> </target> </generator> diff --git a/v1_17_R1/pom.xml b/v1_17_R1/pom.xml index 5ccf039..fa47769 100644 --- a/v1_17_R1/pom.xml +++ b/v1_17_R1/pom.xml @@ -77,22 +77,10 @@ <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven/</url> - </repository> - <repository> - <id>lumine</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> - <repository> - <id>lumine-snapshots</id> - <url>https://mvn.lumine.io/repository/maven-snapshots/</url> - </repository> - <repository> - <id>lumine-test</id> - <url>https://mvn.lumine.io/repository/maven-test/</url> - </repository> + <repository> + <id>lumine</id> + <url>https://mvn.lumine.io/repository/maven/</url> + </repository> <repository> <id>minecraft-libraries</id> <name>Minecraft Libraries</name> diff --git a/v1_18_R1/pom.xml b/v1_18_R1/pom.xml index b4efc54..78e8fea 100644 --- a/v1_18_R1/pom.xml +++ b/v1_18_R1/pom.xml @@ -77,22 +77,10 @@ <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven/</url> - </repository> - <repository> - <id>lumine</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> - <repository> - <id>lumine-snapshots</id> - <url>https://mvn.lumine.io/repository/maven-snapshots/</url> - </repository> - <repository> - <id>lumine-test</id> - <url>https://mvn.lumine.io/repository/maven-test/</url> - </repository> + <repository> + <id>lumine</id> + <url>https://mvn.lumine.io/repository/maven/</url> + </repository> <repository> <id>paper-repo</id> <url>https://papermc.io/repo/repository/maven-public/</url> diff --git a/v1_18_R2/pom.xml b/v1_18_R2/pom.xml index bf90647..4019701 100644 --- a/v1_18_R2/pom.xml +++ b/v1_18_R2/pom.xml @@ -74,21 +74,9 @@ <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven/</url> - </repository> <repository> <id>lumine</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> - <repository> - <id>lumine-snapshots</id> - <url>https://mvn.lumine.io/repository/maven-snapshots/</url> - </repository> - <repository> - <id>lumine-test</id> - <url>https://mvn.lumine.io/repository/maven-test/</url> + <url>https://mvn.lumine.io/repository/maven/</url> </repository> <repository> <id>paper-repo</id> diff --git a/v1_19_R1/pom.xml b/v1_19_R1/pom.xml index 2ea0b22..328286e 100644 --- a/v1_19_R1/pom.xml +++ b/v1_19_R1/pom.xml @@ -74,21 +74,9 @@ <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven/</url> - </repository> <repository> <id>lumine</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> - <repository> - <id>lumine-snapshots</id> - <url>https://mvn.lumine.io/repository/maven-snapshots/</url> - </repository> - <repository> - <id>lumine-test</id> - <url>https://mvn.lumine.io/repository/maven-test/</url> + <url>https://mvn.lumine.io/repository/maven/</url> </repository> <repository> <id>paper-repo</id> diff --git a/v1_19_R1_2/pom.xml b/v1_19_R1_2/pom.xml index 75fe5b0..23fb382 100644 --- a/v1_19_R1_2/pom.xml +++ b/v1_19_R1_2/pom.xml @@ -74,21 +74,9 @@ <id>spigot-repo</id> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> </repository> - <repository> - <id>nexus</id> - <url>https://mvn.lumine.io/repository/maven/</url> - </repository> <repository> <id>lumine</id> - <url>https://mvn.lumine.io/repository/maven-private/</url> - </repository> - <repository> - <id>lumine-snapshots</id> - <url>https://mvn.lumine.io/repository/maven-snapshots/</url> - </repository> - <repository> - <id>lumine-test</id> - <url>https://mvn.lumine.io/repository/maven-test/</url> + <url>https://mvn.lumine.io/repository/maven/</url> </repository> <repository> <id>paper-repo</id> diff --git a/v1_19_R2/.gitignore b/v1_19_R2/.gitignore new file mode 100644 index 0000000..e3425b9 --- /dev/null +++ b/v1_19_R2/.gitignore @@ -0,0 +1 @@ +/.flattened-pom.xml diff --git a/v1_19_R2/pom.xml b/v1_19_R2/pom.xml new file mode 100644 index 0000000..0262f4a --- /dev/null +++ b/v1_19_R2/pom.xml @@ -0,0 +1,164 @@ + <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>MCCosmetics-v1_19_R2</artifactId> + <parent> + <groupId>io.lumine</groupId> + <artifactId>MCCosmetics-Plugin</artifactId> + <version>${mccosmetics.version}</version> + </parent> + + <build> + <plugins> + <plugin> + <groupId>net.md-5</groupId> + <artifactId>specialsource-maven-plugin</artifactId> + <version>1.2.3</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>remap</goal> + </goals> + <id>remap-obf</id> + <configuration> + <srgIn>org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang</srgIn> + <reverse>true</reverse> + <remappedDependencies>org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies> + <remappedArtifactAttached>true</remappedArtifactAttached> + <remappedClassifierName>remapped-obf</remappedClassifierName> + </configuration> + </execution> + <execution> + <phase>package</phase> + <goals> + <goal>remap</goal> + </goals> + <id>remap-spigot</id> + <configuration> + <inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile> + <srgIn>org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn> + <remappedDependencies>org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>flatten-maven-plugin</artifactId> + <version>1.2.2</version> + <configuration> + <updatePomFile>true</updatePomFile> + </configuration> + <executions> + <execution> + <id>flatten</id> + <phase>package</phase> + <goals> + <goal>flatten</goal> + </goals> + </execution> + <execution> + <id>flatten.clean</id> + <phase>clean</phase> + <goals> + <goal>clean</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + <repositories> + <repository> + <id>spigot-repo</id> + <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> + </repository> + <repository> + <id>lumine</id> + <url>https://mvn.lumine.io/repository/maven/</url> + </repository> + <repository> + <id>paper-repo</id> + <url>https://papermc.io/repo/repository/maven-public/</url> + </repository> + <repository> + <id>minecraft-libraries</id> + <name>Minecraft Libraries</name> + <url>https://libraries.minecraft.net</url> + </repository> + </repositories> + + <dependencies> + <!-- Modules --> + <dependency> + <groupId>io.lumine</groupId> + <artifactId>LumineUtils</artifactId> + <version>${lumineutils.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>io.lumine</groupId> + <artifactId>MCCosmetics</artifactId> + <version>${project.parent.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>provided</scope> + </dependency> + + <!-- Spigot API --> + <dependency> + <groupId>org.spigotmc</groupId> + <artifactId>spigot-api</artifactId> + <version>1.19.3-R0.1-SNAPSHOT</version> + <classifier>shaded</classifier> + <scope>provided</scope> + </dependency> + + <!-- Spigot NMS version --> + <dependency> + <groupId>org.spigotmc</groupId> + <artifactId>spigot</artifactId> + <version>1.19.3-R0.1-SNAPSHOT</version> + <classifier>remapped-mojang</classifier> + <scope>provided</scope> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.mojang</groupId> + <artifactId>authlib</artifactId> + <version>3.11.50</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.mojang</groupId> + <artifactId>datafixerupper</artifactId> + <version>1.0.20</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>4.1.68.Final</version> + <scope>provided</scope> + </dependency> + + <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.8.0-beta4</version> + </dependency> + + </dependencies> + +</project> \ No newline at end of file diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/VolatileCodeEnabled_v1_19_R2.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/VolatileCodeEnabled_v1_19_R2.java new file mode 100644 index 0000000..d54012c --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/VolatileCodeEnabled_v1_19_R2.java @@ -0,0 +1,184 @@ +package io.lumine.cosmetics.nms; + +import com.google.common.collect.Maps; +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.api.cosmetics.Cosmetic; +import io.lumine.cosmetics.api.players.wardrobe.Mannequin; +import io.lumine.cosmetics.api.players.wardrobe.WardrobeTracker; +import io.lumine.cosmetics.managers.back.BackAccessory; +import io.lumine.cosmetics.managers.gestures.Gesture; +import io.lumine.cosmetics.managers.hats.Hat; +import io.lumine.cosmetics.managers.offhand.Offhand; +import io.lumine.cosmetics.managers.sprays.Spray; +import io.lumine.cosmetics.nms.cosmetic.VolatileCosmeticHelper; +import io.lumine.cosmetics.nms.v1_19_R2.cosmetic.*; +import io.lumine.cosmetics.nms.v1_19_R2.network.VolatileChannelHandler; +import io.lumine.cosmetics.nms.v1_19_R2.wardrobe.MannequinEntity; +import io.netty.channel.Channel; +import io.netty.channel.ChannelPipeline; +import lombok.Getter; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.entity.LevelEntityGetter; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Map; + +public class VolatileCodeEnabled_v1_19_R2 implements VolatileCodeHandler { + + @Getter private final MCCosmeticsPlugin plugin; + private final Map<Class<? extends Cosmetic>, VolatileCosmeticHelper> cosmeticHelpers = Maps.newConcurrentMap(); + + private Method entityGetter; + + public VolatileCodeEnabled_v1_19_R2(MCCosmeticsPlugin plugin) { + this.plugin = plugin; + cosmeticHelpers.put(Hat.class, new VolatileHatImpl(plugin, this)); + cosmeticHelpers.put(BackAccessory.class, new VolatileBackImpl(plugin, this)); + cosmeticHelpers.put(Spray.class, new VolatileSprayImpl(plugin, this)); + cosmeticHelpers.put(Offhand.class, new VolatileOffhandImpl(plugin, this)); + cosmeticHelpers.put(Gesture.class, new VolatileGestureImpl(plugin, this)); + + for(var method : ServerLevel.class.getMethods()) { + if(LevelEntityGetter.class.isAssignableFrom(method.getReturnType()) && method.getReturnType() != LevelEntityGetter.class) { + entityGetter = method; + break; + } + } + } + + @Override + public VolatileCosmeticHelper getCosmeticHelper(Class<? extends Cosmetic> tClass) { + return cosmeticHelpers.get(tClass); + } + + @Override + public Collection<VolatileCosmeticHelper> getCosmeticHelpers() { + return cosmeticHelpers.values(); + } + + @Override + public void injectPlayer(Player player) { + ServerPlayer ply = ((CraftPlayer) player).getHandle(); + VolatileChannelHandler cdh = new VolatileChannelHandler(player, this); + + ChannelPipeline pipeline = ply.connection.getConnection().channel.pipeline(); + for (String name : pipeline.toMap().keySet()) { + if (pipeline.get(name) instanceof Connection) { + pipeline.addBefore(name, "mc_cosmetics_packet_handler", cdh); + break; + } + } + } + + @Override + public void removePlayer(Player player) { + Channel channel = ((CraftPlayer) player).getHandle().connection.getConnection().channel; + channel.eventLoop().submit(() -> { + channel.pipeline().remove("mc_cosmetics_packet_handler"); + return null; + }); + } + + public void broadcast(Packet<?>... packets) { + for(Player player : Bukkit.getOnlinePlayers()) { + var connection = ((CraftPlayer) player).getHandle().connection; + for(Packet<?> packet : packets) { + connection.send(packet); + } + } + } + + public void broadcast(Player player, Packet<?>... packets) { + var connection = ((CraftPlayer) player).getHandle().connection; + for(Packet<?> packet : packets) { + connection.send(packet); + } + } + + public void broadcastAroundAndSelf(Player wearer, Packet<?>... packets) { + final var level = ((CraftWorld) wearer.getWorld()).getHandle(); + final var trackedEntity = level.getChunkSource().chunkMap.entityMap.get(wearer.getEntityId()); + + if(trackedEntity == null) { + broadcast(wearer.getWorld(), packets); + return; + } + + for(Packet<?> packet : packets) + trackedEntity.broadcastAndSend(packet); + } + + public void broadcastAround(Player wearer, Packet<?>... packets) { + final var level = ((CraftWorld) wearer.getWorld()).getHandle(); + final var trackedEntity = level.getChunkSource().chunkMap.entityMap.get(wearer.getEntityId()); + + if(trackedEntity == null) { + broadcast(wearer.getWorld(), packets); + return; + } + + for(Packet<?> packet : packets) + trackedEntity.broadcast(packet); + } + + public void broadcast(World world, Packet<?>... packets) { + for(Player player : world.getPlayers()) { + var connection = ((CraftPlayer) player).getHandle().connection; + for(Packet<?> packet : packets) { + connection.send(packet); + } + } + } + + public Entity getEntity(World world, int id) { + ServerLevel level = ((CraftWorld) world).getHandle(); + + try { + var getter = entityGetter != null ? + (LevelEntityGetter<net.minecraft.world.entity.Entity>) entityGetter.invoke(level) : + level.entityManager.getEntityGetter(); + + final var entity = getter.get(id); + return entity == null ? null : entity.getBukkitEntity(); + } catch(Exception | Error ex) { + ex.printStackTrace(); + return null; + } + } + + @Override + public Mannequin createMannequin(WardrobeTracker tracker, Player player, Location location) { + return new MannequinEntity(tracker,this,player,location); + } + + @Override + public void removeFakeEntity(int id) { + ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(id); + broadcast(packet); + } + + @Override + public void setBodyYaw(LivingEntity entity, double yaw) { + ((CraftLivingEntity) entity).getHandle().yBodyRot = (float) yaw; + } + + @Override + public float getBodyYaw(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle().yBodyRot; + } +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileBackImpl.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileBackImpl.java new file mode 100644 index 0000000..b384671 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileBackImpl.java @@ -0,0 +1,305 @@ +package io.lumine.cosmetics.nms.v1_19_R2.cosmetic; + +import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.api.cosmetics.Cosmetic; +import io.lumine.cosmetics.api.cosmetics.EquippedCosmetic; +import io.lumine.cosmetics.api.cosmetics.ItemCosmetic; +import io.lumine.cosmetics.api.players.CosmeticProfile; +import io.lumine.cosmetics.api.players.wardrobe.Mannequin; +import io.lumine.cosmetics.constants.CosmeticType; +import io.lumine.cosmetics.logging.MCLogger; +import io.lumine.cosmetics.managers.back.BackAccessory; +import io.lumine.cosmetics.managers.offhand.Offhand; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper; +import io.lumine.cosmetics.nms.v1_19_R2.wardrobe.MannequinEntity; +import io.lumine.cosmetics.players.Profile; +import io.netty.buffer.Unpooled; +import lombok.Getter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class VolatileBackImpl implements VolatileEquipmentHelper { + + @Getter + private final MCCosmeticsPlugin plugin; + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + private final Map<Player, ArmorStand> activeProfile = Maps.newConcurrentMap(); + private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap(); + + public VolatileBackImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.plugin = plugin; + this.nmsHandler = nmsHandler; + } + + @Override + public void apply(CosmeticProfile profile) { + if (profile == null) + return; + Player player = profile.getPlayer(); + + var maybeEquipped = profile.getEquipped(BackAccessory.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equipped = maybeEquipped.get(); + var cosmetic = equipped.getCosmetic(); + + if (!(cosmetic instanceof ItemCosmetic back)) { + return; + } + + var nmsPlayer = ((CraftPlayer) player).getHandle(); + var nmsBack = CraftItemStack.asNMSCopy(back.getCosmetic(equipped)); + + ArmorStand stand = activeProfile.get(player); + if(stand == null) { + playerTracker.put(player.getEntityId(), player); + stand = new ArmorStand(EntityType.ARMOR_STAND, ((CraftWorld) player.getWorld()).getHandle()); + stand.moveTo(nmsPlayer.getX(), nmsPlayer.getY() + nmsPlayer.getPassengersRidingOffset() + stand.getMyRidingOffset(), nmsPlayer.getZ(), nmsPlayer.getYRot(), 0); + stand.setMarker(true); + stand.setInvisible(true); + stand.setSilent(true); + + activeProfile.put(player, stand); + + var mobPacket = new ClientboundAddEntityPacket(stand); + var dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData().getNonDefaultValues()); + var passengersPacket = createPassengerPacket(player.getEntityId(), stand.getId()); + + nmsHandler.broadcastAroundAndSelf(player, mobPacket, dataPacket, passengersPacket); + } + + stand.setItemSlot(EquipmentSlot.HEAD, nmsBack); + + var equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsBack))); + + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + } + + @Override + public void unapply(CosmeticProfile profile) { + Player player = profile.getPlayer(); + ArmorStand stand = activeProfile.remove(player); + if(stand == null) + return; + playerTracker.remove(player.getEntityId()); + ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(stand.getId()); + nmsHandler.broadcastAroundAndSelf(player, removePacket); + } + + @Override + public void equipMannequin(Mannequin mannequin, EquippedCosmetic cosmetic) { + if(!(cosmetic.getCosmetic() instanceof BackAccessory back)) { + return; + } + + final var entityId = mannequin.getEntityId(); + final var player = mannequin.getPlayer(); + var nmsBack = CraftItemStack.asNMSCopy(back.getCosmetic(cosmetic)); + + var mannequinLocation = mannequin.getLocation(); + + mannequin.removeExtraEntity(BackAccessory.class); + + var stand = new ArmorStand(EntityType.ARMOR_STAND, ((CraftWorld) player.getWorld()).getHandle()); + stand.moveTo(mannequinLocation.getX(), mannequinLocation.getY() + stand.getMyRidingOffset(), mannequinLocation.getZ(), mannequinLocation.getYaw(), 0); + stand.setMarker(true); + stand.setInvisible(true); + stand.setSilent(true); + + mannequin.addExtraEntity(BackAccessory.class, stand.getId()); + + var mobPacket = new ClientboundAddEntityPacket(stand); + var dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData().getNonDefaultValues()); + var passengersPacket = createPassengerPacket(entityId, stand.getId()); + + nmsHandler.broadcast(player, mobPacket, dataPacket, passengersPacket); + + stand.setItemSlot(EquipmentSlot.HEAD, nmsBack); + + var equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsBack))); + + nmsHandler.broadcast(player, equipmentPacket); + } + + @Override + public void unequipMannequin(Mannequin mannequin) { + mannequin.removeExtraEntity(BackAccessory.class); + } + + @Override + public boolean read(Player sender, Object packet, boolean isCanceled) { + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(sender); + if(profile == null || profile.isHidden(BackAccessory.class)) + return true; + if(packet instanceof ServerboundMovePlayerPacket) { + handleRotate(profile); + }else if(packet instanceof ServerboundAcceptTeleportationPacket) { + final var list = handleSpawn(profile); + if(list == null) + return true; + final var connection = ((CraftPlayer) sender).getHandle().connection; + for(Object obj : list) { + connection.send((Packet<?>) obj); + } + } + return true; + } + + @Override + public List<Object> write(Player receiver, Object packet) { + if(packet instanceof ClientboundAddPlayerPacket playerPacket) { + int id = playerPacket.getEntityId(); + if(playerTracker.containsKey(id)) { + final var spawnedPlayer = playerTracker.get(id); + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer); + if(profile == null || profile.isHidden(BackAccessory.class)) + return null; + return handleSpawn(profile); + } + }else if(packet instanceof ClientboundRemoveEntitiesPacket removePacket) { + for(int id : removePacket.getEntityIds()) { + if(playerTracker.containsKey(id)) { + return handleDespawn(playerTracker.get(id)); + } + } + } + /* + else if(packet instanceof ClientboundMoveEntityPacket moveEntityPacket) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + moveEntityPacket.write(byteBuf); + int id = byteBuf.readVarInt(); + if(playerTracker.containsKey(id)) { + final var spawnedPlayer = playerTracker.get(id); + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer); + if(profile == null || profile.isHidden(BackAccessory.class)) + return null; + return handleMove(profile, moveEntityPacket); + } + }else if(packet instanceof ClientboundTeleportEntityPacket teleportEntityPacket) { + int id = teleportEntityPacket.getId(); + if(playerTracker.containsKey(id)) { + final var spawnedPlayer = playerTracker.get(id); + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer); + if(profile == null || profile.isHidden(BackAccessory.class)) + return null; + return handleTeleport(profile); + } + }*/ + + return null; + } + + private void handleRotate(Profile profile) { + if(!hasBack(profile)) + return; + + final var wearer = profile.getPlayer(); + final var nmsPlayer = ((CraftPlayer) wearer).getHandle(); + final var stand = activeProfile.get(wearer); + + ClientboundRotateHeadPacket packet = new ClientboundRotateHeadPacket(stand, VolatileEquipmentHelper.toByte(nmsPlayer.getYRot())); + nmsHandler.broadcastAroundAndSelf(wearer, packet); + } + + private List<Object> handleSpawn(Profile profile) { + if(!hasBack(profile)) + return null; + + final var wearer = profile.getPlayer(); + final var stand = activeProfile.get(wearer); + + var mobPacket = new ClientboundAddEntityPacket(stand); + ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(stand.getId(), stand.getEntityData().getNonDefaultValues()); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(stand.getId(), List.of(Pair.of(EquipmentSlot.HEAD, stand.getItemBySlot(EquipmentSlot.HEAD)))); + ClientboundSetPassengersPacket passengersPacket = createPassengerPacket(wearer.getEntityId(), stand.getId()); + + return List.of(mobPacket, dataPacket, equipmentPacket, passengersPacket); + } + + private List<Object> handleDespawn(Player player) { + final var stand = activeProfile.get(player); + if(stand == null) + return null; + ClientboundRemoveEntitiesPacket removePacket = new ClientboundRemoveEntitiesPacket(stand.getId()); + return List.of(removePacket); + } + + private List<Object> handleMove(Profile profile, ClientboundMoveEntityPacket moveEntityPacket) { + if(!hasBack(profile)) + return null; + + final var wearer = profile.getPlayer(); + final var stand = activeProfile.get(wearer); + + ClientboundMoveEntityPacket move; + if(moveEntityPacket.hasPosition() && moveEntityPacket.hasRotation()) { + move = new ClientboundMoveEntityPacket.PosRot( + stand.getId(), + moveEntityPacket.getXa(), + moveEntityPacket.getYa(), + moveEntityPacket.getZa(), + moveEntityPacket.getyRot(), + moveEntityPacket.getxRot(), + false); + }else if(moveEntityPacket.hasPosition()) { + move = new ClientboundMoveEntityPacket.Pos( + stand.getId(), + moveEntityPacket.getXa(), + moveEntityPacket.getYa(), + moveEntityPacket.getZa(), + false); + }else { + move = new ClientboundMoveEntityPacket.Rot( + stand.getId(), + moveEntityPacket.getyRot(), + moveEntityPacket.getxRot(), + false); + } + return List.of(move); + } + + private List<Object> handleTeleport(Profile profile) { + if(!hasBack(profile)) + return null; + + final var wearer = profile.getPlayer(); + final var nmsPlayer = ((CraftPlayer) wearer).getHandle(); + final var stand = activeProfile.get(wearer); + stand.moveTo(nmsPlayer.getX(), nmsPlayer.getY() + nmsPlayer.getPassengersRidingOffset() + stand.getMyRidingOffset(), nmsPlayer.getZ(), nmsPlayer.getYRot(), 0); + + return List.of(new ClientboundTeleportEntityPacket(stand)); + } + + private boolean hasBack(Profile profile) { + if(profile == null) + return false; + + var maybeBack = profile.getEquipped(BackAccessory.class); + return maybeBack.isPresent() && maybeBack.get().getCosmetic() instanceof ItemCosmetic && activeProfile.containsKey(profile.getPlayer()); + } + + private ClientboundSetPassengersPacket createPassengerPacket(int mount, int... driver) { + FriendlyByteBuf bb = new FriendlyByteBuf(Unpooled.buffer()); + bb.writeVarInt(mount); + bb.writeVarIntArray(driver); + return new ClientboundSetPassengersPacket(bb); + } + +} \ No newline at end of file diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileGestureImpl.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileGestureImpl.java new file mode 100644 index 0000000..d27c988 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileGestureImpl.java @@ -0,0 +1,178 @@ +package io.lumine.cosmetics.nms.v1_19_R2.cosmetic; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.mojang.datafixers.util.Pair; +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.api.cosmetics.manager.HideableCosmetic; +import io.lumine.cosmetics.api.players.CosmeticProfile; +import io.lumine.cosmetics.managers.gestures.Gesture; +import io.lumine.cosmetics.managers.gestures.GestureManager; +import io.lumine.cosmetics.managers.gestures.QuitMethod; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper; +import io.lumine.cosmetics.players.Profile; +import io.netty.buffer.Unpooled; +import lombok.Getter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.animal.horse.Horse; +import net.minecraft.world.item.ItemStack; +import org.bukkit.attribute.Attribute; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.attribute.CraftAttributeMap; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class VolatileGestureImpl implements VolatileEquipmentHelper { + + private static final List<Pair<EquipmentSlot, ItemStack>> empty = new ArrayList<>(); + + static { + for(final var slot : EquipmentSlot.values()) + empty.add(Pair.of(slot, ItemStack.EMPTY)); + } + + @Getter + private final MCCosmeticsPlugin plugin; + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + private final Set<Player> activeProfile = Sets.newConcurrentHashSet(); + private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap(); + + private Horse horse; + + public VolatileGestureImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.plugin = plugin; + this.nmsHandler = nmsHandler; + } + + @Override + public void apply(CosmeticProfile profile) { + if (profile == null) + return; + Player player = profile.getPlayer(); + if(activeProfile.contains(player)) + return; + + final var maybeEquipped = profile.getEquipped(Gesture.class); + if(maybeEquipped.isEmpty()) { + return; + } + var opt = maybeEquipped.get().getCosmetic(); + + if(!(opt instanceof Gesture gesture)) + return; + + playerTracker.put(player.getEntityId(), player); + activeProfile.add(player); + if(!gesture.isCanMove()) + getHorsed(player); + player.setInvisible(true); + + for(final var value : ((Profile) profile).getEquipped().values()) { + final var manager = value.getCosmetic().getManager(); + if(!(manager instanceof HideableCosmetic hide)) + continue; + hide.hide(profile, gesture); + } + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), empty); + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + } + + @Override + public void unapply(CosmeticProfile profile) { + if (profile == null) + return; + Player player = profile.getPlayer(); + if(!activeProfile.contains(player)) + return; + + activeProfile.remove(player); + playerTracker.remove(player.getEntityId()); + nmsHandler.broadcast(player, new ClientboundRemoveEntitiesPacket(horse.getId())); + + final var nmsPlayer = ((CraftPlayer) player).getHandle(); + List<Pair<EquipmentSlot, ItemStack>> equipment = new ArrayList<>(); + for(EquipmentSlot slot : EquipmentSlot.values()) + equipment.add(Pair.of(slot, nmsPlayer.getItemBySlot(slot))); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), equipment); + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + + player.setInvisible(false); + for(final var value : ((Profile) profile).getEquipped().values()) { + final var manager = value.getCosmetic().getManager(); + if(!(manager instanceof HideableCosmetic hide)) + continue; + hide.show(profile); + } + } + + private ClientboundSetPassengersPacket createPassengerPacket(int mount, int... driver) { + FriendlyByteBuf bb = new FriendlyByteBuf(Unpooled.buffer()); + bb.writeVarInt(mount); + bb.writeVarIntArray(driver); + return new ClientboundSetPassengersPacket(bb); + } + + private void getHorsed(Player player) { + final var nmsPlayer = ((CraftPlayer) player).getHandle(); + + if(horse == null) { + horse = new Horse(EntityType.HORSE, ((CraftWorld) player.getWorld()).getHandle()); + horse.setInvisible(true); + horse.setHealth(0); + horse.getAttribute(CraftAttributeMap.toMinecraft(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(0); + } + horse.setPos(nmsPlayer.getX(), nmsPlayer.getY() - horse.getPassengersRidingOffset() - nmsPlayer.getMyRidingOffset(), nmsPlayer.getZ()); + + var mobPacket = new ClientboundAddEntityPacket(horse); + var dataPacket = new ClientboundSetEntityDataPacket(horse.getId(), horse.getEntityData().getNonDefaultValues()); + var attributesPacket = new ClientboundUpdateAttributesPacket(horse.getId(), horse.getAttributes().getSyncableAttributes()); + var passengersPacket = createPassengerPacket(horse.getId(), nmsPlayer.getId()); + + nmsHandler.broadcast(player, mobPacket, dataPacket, attributesPacket, passengersPacket); + } + + @Override + public boolean read(Player sender, Object packet, boolean isCanceled) { + if(!plugin.getGestureManager().getTicking().containsKey(sender)) { + return true; + } + + if(packet instanceof ServerboundPlayerInputPacket inputPacket) { + final var manager = (GestureManager) plugin.getGestureManager(); + if(inputPacket.isShiftKeyDown()) + manager.quit(sender, QuitMethod.SNEAK); + if(inputPacket.isJumping()) + manager.quit(sender, QuitMethod.JUMP); + }else if(packet instanceof ServerboundSetCarriedItemPacket setSlotPacket) { + int oSlot = sender.getInventory().getHeldItemSlot(); + if(oSlot != setSlotPacket.getSlot()) { + nmsHandler.broadcast(sender, new ClientboundSetCarriedItemPacket(oSlot)); + return false; + } + } + return true; + } + + @Override + public List<Object> write(Player receiver, Object packet) { + if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) { + int id = equipmentPacket.getEntity(); + final var spawnedPlayer = playerTracker.get(id); + if(spawnedPlayer == null) + return null; + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(spawnedPlayer); + if(profile != null) + return List.of(new ClientboundSetEquipmentPacket(id, empty)); + } + return null; + } +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileHatImpl.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileHatImpl.java new file mode 100644 index 0000000..c5831f6 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileHatImpl.java @@ -0,0 +1,199 @@ +package io.lumine.cosmetics.nms.v1_19_R2.cosmetic; + +import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.api.cosmetics.EquippedCosmetic; +import io.lumine.cosmetics.api.cosmetics.ItemCosmetic; +import io.lumine.cosmetics.api.players.CosmeticProfile; +import io.lumine.cosmetics.api.players.wardrobe.Mannequin; +import io.lumine.cosmetics.managers.hats.Hat; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper; +import io.lumine.cosmetics.players.Profile; +import io.lumine.utils.logging.Log; +import io.lumine.utils.reflection.Reflector; +import io.netty.buffer.Unpooled; +import lombok.Getter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket; +import net.minecraft.world.entity.EquipmentSlot; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class VolatileHatImpl implements VolatileEquipmentHelper { + + @Getter private final MCCosmeticsPlugin plugin; + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + //private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap(); + + public VolatileHatImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.plugin = plugin; + this.nmsHandler = nmsHandler; + } + + @Override + public void apply(CosmeticProfile profile) { + + if (profile == null) + return; + + Player player = profile.getPlayer(); + + final var maybeEquipped = profile.getEquipped(Hat.class); + if(maybeEquipped.isEmpty()) { + return; + } + var opt = maybeEquipped.get().getCosmetic(); + + if(!(opt instanceof Hat hat)) + return; + + var nmsHat = CraftItemStack.asNMSCopy(hat.getCosmetic(maybeEquipped.get())); + + //playerTracker.put(player.getEntityId(), player); + + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsHat))); + + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + } + + @Override + public void unapply(CosmeticProfile profile) { + final var nmsPlayer = ((CraftPlayer) profile.getPlayer()).getHandle(); + final var item = nmsPlayer.getItemBySlot(EquipmentSlot.HEAD); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.HEAD, item))); + nmsHandler.broadcastAroundAndSelf(nmsPlayer.getBukkitEntity(), equipmentPacket); + } + + @Override + public void equipMannequin(Mannequin mannequin, EquippedCosmetic cosmetic) { + if(!(cosmetic.getCosmetic() instanceof Hat hat)) { + return; + } + + final var entityId = mannequin.getEntityId(); + final var player = mannequin.getPlayer(); + + var nmsHat = CraftItemStack.asNMSCopy(hat.getCosmetic(cosmetic)); + + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(entityId, + List.of(Pair.of(EquipmentSlot.HEAD, nmsHat))); + + nmsHandler.broadcast(player, equipmentPacket); + } + + @Override + public void unequipMannequin(Mannequin mannequin) { + final var nmsPlayer = ((CraftPlayer) mannequin.getPlayer()).getHandle(); + final var item = nmsPlayer.getItemBySlot(EquipmentSlot.HEAD); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.HEAD, item))); + nmsHandler.broadcast(nmsPlayer.getBukkitEntity(), equipmentPacket); + } + + @Override + public boolean read(Player sender, Object packet, boolean isCanceled) { + if(packet instanceof ServerboundAcceptTeleportationPacket) { + final var profile = MCCosmeticsPlugin.inst().getProfiles().getProfile(sender); + if(profile == null || profile.isHidden(Hat.class)) + return true; + handleSpawn(profile); + } + return true; + } + + @Override + public List<Object> write(Player receiver, Object packet) { + /* + if(packet instanceof ClientboundAddPlayerPacket playerPacket) { + int id = playerPacket.getEntityId(); + Profile profile = getProfile(receiver, id); + if(profile != null && !profile.isHidden(Hat.class)) { + handleSpawn(profile); + } + } else */ + + if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) { + int id = equipmentPacket.getEntity(); + Profile profile = getProfile(receiver, id); + if(profile != null && !profile.isHidden(Hat.class)) { + modifyPacket(profile, equipmentPacket); + } + } + + return null; + } + + private Profile getProfile(Player receiver, int id) { + final var entity = nmsHandler.getEntity(receiver.getWorld(), id); + if(!(entity instanceof Player player)) + return null; + return plugin.getProfiles().getProfile(player); + } + + public void handleSpawn(Profile profile) { + + final var maybeEquipped = profile.getEquipped(Hat.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equip = maybeEquipped.get(); + var opt = equip.getCosmetic(); + + if(!(opt instanceof ItemCosmetic hat)) { + return; + } + + final var player = profile.getPlayer(); + final var nmsHat = CraftItemStack.asNMSCopy(hat.getCosmetic(equip)); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.HEAD, nmsHat))); + + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + } + + private static Reflector<ClientboundSetEquipmentPacket> refEq = new Reflector(ClientboundSetEquipmentPacket.class, "c"); + + private void modifyPacket(Profile profile, ClientboundSetEquipmentPacket packet) { + final var maybeEquipped = profile.getEquipped(Hat.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equip = maybeEquipped.get(); + var opt = equip.getCosmetic(); + + if(!(opt instanceof ItemCosmetic hat)) { + return; + } + + final var nmsItem = CraftItemStack.asNMSCopy(hat.getCosmetic(equip)); + + var slots = (List<Pair<EquipmentSlot,net.minecraft.world.item.ItemStack>>) packet.getSlots(); + List<Pair<EquipmentSlot,net.minecraft.world.item.ItemStack>> newSlots = new ArrayList<>(); + + boolean foundHead = false; + for(var pair : slots) { + final EquipmentSlot slot = pair.getFirst(); + + if(slot == EquipmentSlot.HEAD) { + foundHead = true; + newSlots.add(Pair.of(pair.getFirst(), nmsItem)); + } else { + newSlots.add(pair); + } + } + if(!foundHead) { + newSlots.add(Pair.of(EquipmentSlot.HEAD, nmsItem)); + } + + refEq.set(packet, "c", newSlots); + } + +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileOffhandImpl.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileOffhandImpl.java new file mode 100644 index 0000000..0a7b627 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileOffhandImpl.java @@ -0,0 +1,173 @@ +package io.lumine.cosmetics.nms.v1_19_R2.cosmetic; + +import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.api.cosmetics.EquippedCosmetic; +import io.lumine.cosmetics.api.cosmetics.ItemCosmetic; +import io.lumine.cosmetics.api.players.CosmeticProfile; +import io.lumine.cosmetics.api.players.wardrobe.Mannequin; +import io.lumine.cosmetics.managers.hats.Hat; +import io.lumine.cosmetics.managers.offhand.Offhand; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.lumine.cosmetics.nms.cosmetic.VolatileEquipmentHelper; +import io.lumine.cosmetics.players.Profile; +import io.lumine.utils.reflection.Reflector; +import io.netty.buffer.Unpooled; +import lombok.Getter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.world.entity.EquipmentSlot; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class VolatileOffhandImpl implements VolatileEquipmentHelper { + + @Getter private final MCCosmeticsPlugin plugin; + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + private final Map<Integer, Player> playerTracker = Maps.newConcurrentMap(); + + public VolatileOffhandImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.plugin = plugin; + this.nmsHandler = nmsHandler; + } + + @Override + public void apply(CosmeticProfile profile) { + + if (profile == null) + return; + + Player player = profile.getPlayer(); + + final var maybeEquipped = profile.getEquipped(Offhand.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equip = maybeEquipped.get(); + var opt = equip.getCosmetic(); + + if(!(opt instanceof ItemCosmetic offhand)) + return; + + var nmsOffhand = CraftItemStack.asNMSCopy(offhand.getCosmetic(equip)); + + playerTracker.put(player.getEntityId(), player); + + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.OFFHAND, nmsOffhand))); + + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + + } + + @Override + public void unapply(CosmeticProfile profile) { + final var nmsPlayer = ((CraftPlayer) profile.getPlayer()).getHandle(); + final var item = nmsPlayer.getItemBySlot(EquipmentSlot.OFFHAND); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.OFFHAND, item))); + nmsHandler.broadcastAroundAndSelf(nmsPlayer.getBukkitEntity(), equipmentPacket); + } + + @Override + public void equipMannequin(Mannequin mannequin, EquippedCosmetic cosmetic) { + if(!(cosmetic.getCosmetic() instanceof Offhand offhand)) { + return; + } + + final var entityId = mannequin.getEntityId(); + final var player = mannequin.getPlayer(); + + var nmsHat = CraftItemStack.asNMSCopy(offhand.getCosmetic(cosmetic)); + + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(entityId, List.of(Pair.of(EquipmentSlot.OFFHAND, nmsHat))); + + nmsHandler.broadcast(player, equipmentPacket); + } + + @Override + public void unequipMannequin(Mannequin mannequin) { + final var nmsPlayer = ((CraftPlayer) mannequin.getPlayer()).getHandle(); + final var item = nmsPlayer.getItemBySlot(EquipmentSlot.OFFHAND); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(nmsPlayer.getId(), List.of(Pair.of(EquipmentSlot.OFFHAND, item))); + nmsHandler.broadcast(nmsPlayer.getBukkitEntity(), equipmentPacket); + } + + @Override + public List<Object> write(Player receiver, Object packet) { + if(packet instanceof ClientboundSetEquipmentPacket equipmentPacket) { + int id = equipmentPacket.getEntity(); + Profile profile = getProfile(receiver, id); + if(profile != null && !profile.isHidden(Offhand.class)) + modifyPacket(profile, equipmentPacket); + } + + return null; + } + + private Profile getProfile(Player receiver, int id) { + final var entity = nmsHandler.getEntity(receiver.getWorld(), id); + if(!(entity instanceof Player player)) + return null; + return plugin.getProfiles().getProfile(player); + } + + public void handleSpawn(Profile profile) { + final var maybeEquipped = profile.getEquipped(Offhand.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equip = maybeEquipped.get(); + var opt = equip.getCosmetic(); + + if(!(opt instanceof ItemCosmetic offhand)) + return; + + final var player = profile.getPlayer(); + final var nmsOffhand = CraftItemStack.asNMSCopy(offhand.getCosmetic(equip)); + ClientboundSetEquipmentPacket equipmentPacket = new ClientboundSetEquipmentPacket(player.getEntityId(), List.of(Pair.of(EquipmentSlot.OFFHAND, nmsOffhand))); + nmsHandler.broadcastAroundAndSelf(player, equipmentPacket); + } + + private static Reflector<ClientboundSetEquipmentPacket> refEq = new Reflector(ClientboundSetEquipmentPacket.class, "c"); + + private void modifyPacket(Profile profile, ClientboundSetEquipmentPacket packet) { + final var maybeEquipped = profile.getEquipped(Hat.class); + if(maybeEquipped.isEmpty()) { + return; + } + var equip = maybeEquipped.get(); + var opt = equip.getCosmetic(); + + if(!(opt instanceof ItemCosmetic hat)) { + return; + } + + final var nmsItem = CraftItemStack.asNMSCopy(hat.getCosmetic(equip)); + + var slots = (List<Pair<EquipmentSlot,net.minecraft.world.item.ItemStack>>) packet.getSlots(); + List<Pair<EquipmentSlot,net.minecraft.world.item.ItemStack>> newSlots = new ArrayList<>(); + + boolean foundHead = false; + for(var pair : slots) { + final EquipmentSlot slot = pair.getFirst(); + + if(slot == EquipmentSlot.HEAD) { + foundHead = true; + newSlots.add(Pair.of(pair.getFirst(), nmsItem)); + } else { + newSlots.add(pair); + } + } + if(!foundHead) { + newSlots.add(Pair.of(EquipmentSlot.HEAD, nmsItem)); + } + refEq.set(packet, "c", newSlots); + } + +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileSprayImpl.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileSprayImpl.java new file mode 100644 index 0000000..57e6029 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/cosmetic/VolatileSprayImpl.java @@ -0,0 +1,90 @@ +package io.lumine.cosmetics.nms.v1_19_R2.cosmetic; + +import io.lumine.cosmetics.MCCosmeticsPlugin; +import io.lumine.cosmetics.managers.sprays.Spray; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.lumine.cosmetics.nms.cosmetic.VolatileSprayHelper; +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.world.entity.decoration.ItemFrame; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; + +public class VolatileSprayImpl implements VolatileSprayHelper { + + @Getter private final MCCosmeticsPlugin plugin; + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + + public VolatileSprayImpl(MCCosmeticsPlugin plugin, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.plugin = plugin; + this.nmsHandler = nmsHandler; + } + + private static final ItemStack map = new ItemStack(Material.FILLED_MAP); + private static final MapMeta mapMeta = (MapMeta) map.getItemMeta(); + + @Override + public int drawSpray(Spray spray, Location location, BlockFace face, int rotation) { + var world = ((CraftWorld) location.getWorld()).getHandle(); + var pos = new BlockPos(location.getX(), location.getY(), location.getZ()); + + var image = spray.getImage(); + + mapMeta.setMapId(image.getMapNumber()); + map.setItemMeta(mapMeta); + + var nmsMap = CraftItemStack.asNMSCopy(map); + + final int dir = switch(face) { + case DOWN -> 0; + case UP -> 1; + case NORTH -> 2; + case SOUTH -> 3; + case WEST -> 4; + case EAST -> 5; + default -> 1; + }; + + var frame = new ItemFrame(world, pos, Direction.UP); + frame.setItem(nmsMap); + frame.setInvisible(true); + frame.setRotation(rotation); + + var packetAdd = new ClientboundAddEntityPacket(frame, dir); + var packetData = new ClientboundSetEntityDataPacket(frame.getId(), frame.getEntityData().getNonDefaultValues()); + var packetMap = constructMapPacket(image.getMapNumber(), image.getPixels()); + + nmsHandler.broadcast(packetAdd, packetData, packetMap); + + return frame.getId(); + } + + private static final int startX = 0; + private static final int startY = 0; + private static final int mapWidth = 128; + private static final int mapHeight = 128; + private static final byte mapScale = 1; + private static final boolean mapLocked = true; + + private ClientboundMapItemDataPacket constructMapPacket(int id, byte[] pixels) { + var mapData = constructMapData(startX, startY, mapWidth, mapHeight, pixels); + var packet = new ClientboundMapItemDataPacket(id, mapScale, mapLocked, null, mapData); + + return packet; + } + + private MapItemSavedData.MapPatch constructMapData(int startX, int startY, int width, int height, byte[] pixels) { + return new MapItemSavedData.MapPatch(startX, startY, width, height, pixels); + } + +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/network/VolatileChannelHandler.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/network/VolatileChannelHandler.java new file mode 100644 index 0000000..017ae70 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/network/VolatileChannelHandler.java @@ -0,0 +1,61 @@ +package io.lumine.cosmetics.nms.v1_19_R2.network; + +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import lombok.Getter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class VolatileChannelHandler extends ChannelDuplexHandler { + + private final VolatileCodeEnabled_v1_19_R2 nmsHandler; + @Getter private final Player player; + + public VolatileChannelHandler(Player player, VolatileCodeEnabled_v1_19_R2 nmsHandler) { + this.player = player; + this.nmsHandler = nmsHandler; + } + + @Override + public void write(ChannelHandlerContext ctx, Object obj, ChannelPromise promise) { + + try { + + List<Object> packets = new ArrayList<>(); + + for(final var helper : nmsHandler.getCosmeticHelpers()) { + final var writes = helper.write(player, obj); + if(writes != null) + packets.addAll(writes); + } + + if(!packets.contains(obj)) + super.write(ctx, obj, promise); + packets.remove(obj); + + for (var p : packets) { + super.write(ctx, p, promise.channel().newPromise()); + } + }catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception { + + boolean isCanceled = false; + for(final var helper : nmsHandler.getCosmeticHelpers()) { + isCanceled |= !helper.read(player, obj, isCanceled); + } + + if(!isCanceled) + super.channelRead(ctx, obj); + } + +} diff --git a/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/wardrobe/MannequinEntity.java b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/wardrobe/MannequinEntity.java new file mode 100644 index 0000000..92b8e21 --- /dev/null +++ b/v1_19_R2/src/main/java/io/lumine/cosmetics/nms/v1_19_R2/wardrobe/MannequinEntity.java @@ -0,0 +1,132 @@ +package io.lumine.cosmetics.nms.v1_19_R2.wardrobe; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mojang.authlib.GameProfile; +import com.mojang.datafixers.util.Pair; + +import io.lumine.cosmetics.api.cosmetics.Cosmetic; +import io.lumine.cosmetics.api.players.wardrobe.Mannequin; +import io.lumine.cosmetics.api.players.wardrobe.WardrobeTracker; +import io.lumine.cosmetics.nms.VolatileCodeEnabled_v1_19_R2; +import io.netty.buffer.Unpooled; +import lombok.Getter; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket; +import net.minecraft.network.protocol.game.ClientboundAnimatePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EquipmentSlot; + +public class MannequinEntity implements Mannequin { + + private final VolatileCodeEnabled_v1_19_R2 handler; + @Getter private final WardrobeTracker tracker; + @Getter private final UUID uniqueId; + @Getter private final Player player; + @Getter private final Location location; + @Getter private float rotation; + + @Getter private ServerPlayer fakePlayer; + private Map<Class<? extends Cosmetic>,Integer> extraEntities = Maps.newConcurrentMap(); + + public MannequinEntity(WardrobeTracker tracker, VolatileCodeEnabled_v1_19_R2 handler, Player player, Location location) { + this.tracker = tracker; + this.handler = handler; + this.player = player; + this.location = location; + this.uniqueId = UUID.randomUUID(); + + var serverPlayer = ((CraftPlayer) player).getHandle(); + var level = ((CraftWorld) location.getWorld()).getHandle(); + + this.rotation = serverPlayer.getYRot() + 180; + + if(rotation > 180) { + rotation = rotation - 360; + } + + var gameProfile = serverPlayer.getGameProfile(); + + gameProfile = new GameProfile(uniqueId, "Wardrobe"); + gameProfile.getProperties().putAll(serverPlayer.getGameProfile().getProperties()); + + this.fakePlayer = new ServerPlayer(level.getServer(), level, gameProfile); + + var spawn = new FriendlyByteBuf(Unpooled.buffer()); + + spawn.writeVarInt(fakePlayer.getId()); + spawn.writeUUID(fakePlayer.getUUID()); + spawn.writeDouble(location.getX()); + spawn.writeDouble(location.getY()); + spawn.writeDouble(location.getZ()); + spawn.writeByte((byte)(int)(serverPlayer.getYRot() * 256.0F / 360.0F)); + spawn.writeByte((byte)(int)(serverPlayer.getXRot() * 256.0F / 360.0F)); + + var packetPlayerInfo = new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, fakePlayer); + var packetAddPlayer = new ClientboundAddPlayerPacket(spawn); + + var equipmentPacket = new ClientboundSetEquipmentPacket(fakePlayer.getId(), + List.of(Pair.of(EquipmentSlot.HEAD, serverPlayer.getItemBySlot(EquipmentSlot.HEAD)), + Pair.of(EquipmentSlot.CHEST, serverPlayer.getItemBySlot(EquipmentSlot.CHEST)), + Pair.of(EquipmentSlot.LEGS, serverPlayer.getItemBySlot(EquipmentSlot.LEGS)), + Pair.of(EquipmentSlot.FEET, serverPlayer.getItemBySlot(EquipmentSlot.FEET)), + Pair.of(EquipmentSlot.MAINHAND, serverPlayer.getItemBySlot(EquipmentSlot.MAINHAND)), + Pair.of(EquipmentSlot.OFFHAND, serverPlayer.getItemBySlot(EquipmentSlot.OFFHAND)))); + + var head = (byte)(int)(rotation * 256.0F / 360.0F); + var rotatePacket = new ClientboundRotateHeadPacket(fakePlayer, head); + + var swingPacket = new ClientboundAnimatePacket(fakePlayer, 0); + + handler.broadcast(player, packetPlayerInfo, packetAddPlayer, equipmentPacket, rotatePacket, swingPacket); + + for(var eq : handler.getPlugin().getProfiles().getProfile(player).getEquipped().values()) { + eq.getCosmetic().getManager().equipMannequin(this, eq); + } + } + + public void despawn() { + var packetPlayerInfo = new ClientboundPlayerInfoRemovePacket(Lists.newArrayList(fakePlayer.getUUID())); + var packetRemovePlayer = new ClientboundRemoveEntitiesPacket(fakePlayer.getId()); + + handler.broadcast(player, packetPlayerInfo, packetRemovePlayer); + + for(var i : extraEntities.values()) { + var removePacket = new ClientboundRemoveEntitiesPacket(i); + handler.broadcast(player, removePacket); + } + } + + public void addExtraEntity(Class<? extends Cosmetic> type, int id) { + extraEntities.put(type, id); + } + + public void removeExtraEntity(Class<? extends Cosmetic> type) { + var id = extraEntities.remove(type); + + if(id != null) { + var removePacket = new ClientboundRemoveEntitiesPacket(id); + handler.broadcast(player, removePacket); + } + } + + public int getEntityId() { + return fakePlayer.getId(); + } + +} -- GitLab