mirror of
https://github.com/HibiscusMC/HMCCosmetics.git
synced 2025-12-19 15:09:19 +00:00
Compare commits
133 Commits
v1.0.1
...
1_11_2_mod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2347c5175d | ||
|
|
977b5e388a | ||
|
|
46c47b0a1f | ||
|
|
4b8d2c1517 | ||
|
|
4d632c612a | ||
|
|
0b4e2a6966 | ||
|
|
23a5ffa068 | ||
|
|
56fa927ca6 | ||
|
|
9c16008f29 | ||
|
|
0dc69241f1 | ||
|
|
cf1e94e116 | ||
|
|
72f92be6f6 | ||
|
|
39ac2713b7 | ||
|
|
a07eec4ddc | ||
|
|
231dcc163e | ||
|
|
d22b13fe05 | ||
|
|
0c54f52785 | ||
|
|
16ede1baab | ||
|
|
1ba07b87cf | ||
|
|
11baacaa5f | ||
|
|
8b231535c9 | ||
|
|
b81241a019 | ||
|
|
4b64ee1b3e | ||
|
|
d2592809c7 | ||
|
|
ffae42c5a7 | ||
|
|
7e4d9459ba | ||
|
|
30f5278ca9 | ||
|
|
6e3de56071 | ||
|
|
3d9c006310 | ||
|
|
3d8b582a8f | ||
|
|
311253aed3 | ||
|
|
8912ab5b94 | ||
|
|
136a5679a6 | ||
|
|
e024d6420b | ||
|
|
7a7ddf09fb | ||
|
|
412688eebc | ||
|
|
4aa3ecc147 | ||
|
|
700ff1aa3f | ||
|
|
929fd84a74 | ||
|
|
cc768d8186 | ||
|
|
85fc9d9056 | ||
|
|
538690612a | ||
|
|
998cc02edd | ||
|
|
cfadc69a0d | ||
|
|
a29d7f20d0 | ||
|
|
4460938dc3 | ||
|
|
8a0ce58297 | ||
|
|
20efcb0b36 | ||
|
|
af05a83451 | ||
|
|
aed81b4a13 | ||
|
|
eec23ab54b | ||
|
|
45c51492a3 | ||
|
|
80f6e02598 | ||
|
|
edc8724e90 | ||
|
|
f7d8a7205f | ||
|
|
3551de2cd3 | ||
|
|
3da27b0bf4 | ||
|
|
b63c130730 | ||
|
|
81db0cab06 | ||
|
|
f02871871c | ||
|
|
7207974ada | ||
|
|
7ea5cdcf46 | ||
|
|
512627d1c7 | ||
|
|
246fd3f9a6 | ||
|
|
70ee381f48 | ||
|
|
d78bf20ca9 | ||
|
|
1c7aa2c672 | ||
|
|
f0a046f434 | ||
|
|
22c4323a16 | ||
|
|
77e913257e | ||
|
|
2cc4fcc878 | ||
|
|
e35eee9937 | ||
|
|
941b82de08 | ||
|
|
81bea485a5 | ||
|
|
cfa36dab4b | ||
|
|
14d1cf5d19 | ||
|
|
8455492322 | ||
|
|
c4dba6f9a8 | ||
|
|
280018fb9f | ||
|
|
14617fdaff | ||
|
|
61f13eb3c1 | ||
|
|
39b6a8de67 | ||
|
|
f19b4d359e | ||
|
|
0ca9350ce6 | ||
|
|
d9f12db6dc | ||
|
|
3c302e6c4b | ||
|
|
e22b776d13 | ||
|
|
915285c485 | ||
|
|
02a3c96137 | ||
|
|
7bb8fd79c2 | ||
|
|
27cab1fb4b | ||
|
|
3c8c585634 | ||
|
|
b2465c8b13 | ||
|
|
3cc489cac9 | ||
|
|
328aacb73d | ||
|
|
3e609dac93 | ||
|
|
14eb7b8edc | ||
|
|
5c9041acfc | ||
|
|
f40c6fc292 | ||
|
|
f800ceaed6 | ||
|
|
a6c5761636 | ||
|
|
bb812a180f | ||
|
|
d69dd1afef | ||
|
|
4a1eb8a85f | ||
|
|
d6c052294a | ||
|
|
32afd0d144 | ||
|
|
66ff99e657 | ||
|
|
67cf6d3267 | ||
|
|
1d988ed809 | ||
|
|
22f095f236 | ||
|
|
cc0b2d75b7 | ||
|
|
520b9854f5 | ||
|
|
f8bc649799 | ||
|
|
44c99ae6d2 | ||
|
|
63681ab9cf | ||
|
|
705664441a | ||
|
|
d7a8cac2e2 | ||
|
|
3cef8dc0e3 | ||
|
|
b054207012 | ||
|
|
1bb80e0fcd | ||
|
|
e9694e77d7 | ||
|
|
a8ba081975 | ||
|
|
6843373298 | ||
|
|
c97c3650ea | ||
|
|
dbdc6a5c90 | ||
|
|
f507dea3c5 | ||
|
|
cb9c7fb551 | ||
|
|
e2406c697c | ||
|
|
0faf05fd61 | ||
|
|
44da234779 | ||
|
|
c7238bb375 | ||
|
|
1ee6fc5f49 | ||
|
|
fa95a6fa33 |
36
.idea/codeStyles/Project.xml
generated
Normal file
36
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="GENERATE_FINAL_LOCALS" value="true" />
|
||||
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
|
||||
<option name="REPLACE_NULL_CHECK" value="false" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999999999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999999" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<arrangement>
|
||||
<groups>
|
||||
<group>
|
||||
<type>GETTERS_AND_SETTERS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>OVERRIDDEN_METHODS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>DEPENDENT_METHODS</type>
|
||||
<order>BREADTH_FIRST</order>
|
||||
</group>
|
||||
</groups>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
6
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
6
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="GoogleStyle" />
|
||||
</state>
|
||||
</component>
|
||||
4
.idea/compiler.xml
generated
4
.idea/compiler.xml
generated
@@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="16" />
|
||||
<bytecodeTargetLevel target="16">
|
||||
<module name="common" target="1.8" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/common/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/common/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/gradle.xml
generated
7
.idea/gradle.xml
generated
@@ -4,11 +4,18 @@
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="delegatedBuild" value="true" />
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="openjdk-16" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/1.17" />
|
||||
<option value="$PROJECT_DIR$/1.18" />
|
||||
<option value="$PROJECT_DIR$/common" />
|
||||
<option value="$PROJECT_DIR$/nms" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
||||
101
.idea/jarRepositories.xml
generated
101
.idea/jarRepositories.xml
generated
@@ -1,15 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://repo.mattstudios.me/artifactory/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven7" />
|
||||
<option name="name" value="maven7" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="paperweightDecompilerRepository" />
|
||||
<option name="name" value="paperweightDecompilerRepository" />
|
||||
<option name="url" value="https://files.minecraftforge.net/maven/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="sonatype" />
|
||||
<option name="name" value="sonatype" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/groups/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="paperweightParamMappingsRepository" />
|
||||
<option name="name" value="paperweightParamMappingsRepository" />
|
||||
<option name="url" value="https://maven.fabricmc.net/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
<option name="id" value="maven6" />
|
||||
<option name="name" value="maven6" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven7" />
|
||||
<option name="name" value="maven7" />
|
||||
<option name="url" value="https://repo.jeff-media.de/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven8" />
|
||||
<option name="name" value="maven8" />
|
||||
<option name="url" value="https://maven.pkg.github.com/LoneDev6/API-ItemsAdder" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven5" />
|
||||
<option name="name" value="maven5" />
|
||||
<option name="url" value="https://repo.leonardobishop.com/releases/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven6" />
|
||||
<option name="name" value="maven6" />
|
||||
<option name="url" value="https://mvnrepository.com/artifact/com.zaxxer/HikariCP" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven8" />
|
||||
<option name="name" value="maven8" />
|
||||
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven4" />
|
||||
@@ -21,35 +81,30 @@
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven6" />
|
||||
<option name="name" value="maven6" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://repo.mattstudios.me/artifactory/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven5" />
|
||||
<option name="name" value="maven5" />
|
||||
<option name="url" value="https://repo.leonardobishop.com/releases/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:/$MAVEN_REPOSITORY$/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven11" />
|
||||
<option name="name" value="maven11" />
|
||||
<option name="url" value="https://libraries.minecraft.net/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven7" />
|
||||
<option name="name" value="maven7" />
|
||||
<option name="url" value="https://repo.dmulloy2.net/repository/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="spigotmc-repo" />
|
||||
<option name="name" value="spigotmc-repo" />
|
||||
<option name="url" value="https://hub.spigotmc.org/nexus/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/kotlinScripting.xml
generated
Normal file
6
.idea/kotlinScripting.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinScriptingSettings">
|
||||
<option name="suppressDefinitionsCheck" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@@ -1,10 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="16" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
16
.idea/modules/1.17/HMCCosmetics.1.17.main.iml
generated
Normal file
16
.idea/modules/1.17/HMCCosmetics.1.17.main.iml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPIGOT</platformType>
|
||||
<platformType>MCP</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="McpModuleSettings">
|
||||
<option name="srgType" value="SRG" />
|
||||
</component>
|
||||
</module>
|
||||
12
.idea/modules/1.17/HMCCosmetics.1.17.test.iml
generated
Normal file
12
.idea/modules/1.17/HMCCosmetics.1.17.test.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
||||
16
.idea/modules/1.18/HMCCosmetics.1.18.main.iml
generated
Normal file
16
.idea/modules/1.18/HMCCosmetics.1.18.main.iml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPIGOT</platformType>
|
||||
<platformType>MCP</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="McpModuleSettings">
|
||||
<option name="srgType" value="SRG" />
|
||||
</component>
|
||||
</module>
|
||||
12
.idea/modules/1.18/HMCCosmetics.1.18.test.iml
generated
Normal file
12
.idea/modules/1.18/HMCCosmetics.1.18.test.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
||||
@@ -4,6 +4,7 @@
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPIGOT</platformType>
|
||||
<platformType>MCP</platformType>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
12
.idea/modules/common/HMCCosmetics.common.test.iml
generated
Normal file
12
.idea/modules/common/HMCCosmetics.common.test.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
||||
16
.idea/modules/nms/HMCCosmetics.nms.main.iml
generated
Normal file
16
.idea/modules/nms/HMCCosmetics.nms.main.iml
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPIGOT</platformType>
|
||||
<platformType>MCP</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="McpModuleSettings">
|
||||
<option name="srgType" value="SRG" />
|
||||
</component>
|
||||
</module>
|
||||
23
1.17/build.gradle.kts
Normal file
23
1.17/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id("java")
|
||||
}
|
||||
|
||||
//group = "io.github.fisher2911"
|
||||
//version = "1.7.1"
|
||||
//description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.dmulloy2.net/repository/public/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":nms"))
|
||||
compileOnly("com.mojang:authlib:1.5.25")
|
||||
compileOnly("org.spigotmc:spigot:1.17-R0.1-SNAPSHOT")
|
||||
compileOnly("org.jetbrains:annotations:22.0.0")
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
|
||||
public class DestroyPacket_1_17_R1 implements DestroyPacket {
|
||||
|
||||
@Override
|
||||
public PacketContainer get(final int entityId) {
|
||||
final PacketContainer destroyPacket = new PacketContainer(
|
||||
PacketType.Play.Server.ENTITY_DESTROY);
|
||||
destroyPacket.getModifier().write(0, new IntArrayList(new int[]{entityId}));
|
||||
|
||||
return destroyPacket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerPackets_1_17_R1 implements PlayerPackets {
|
||||
|
||||
@Override
|
||||
public PacketContainer getSpawnPacket(final Location location, UUID uuid, final int entityId) {
|
||||
final PacketContainer spawnPacket = new PacketContainer(PacketType.Play.Server.NAMED_ENTITY_SPAWN);
|
||||
spawnPacket.getUUIDs().write(0, uuid);
|
||||
spawnPacket.getIntegers().write(0, entityId);
|
||||
spawnPacket.getDoubles().
|
||||
write(0, location.getX()).
|
||||
write(1, location.getY()).
|
||||
write(2, location.getZ());
|
||||
spawnPacket.getBytes().write(0, (byte)(((location.getYaw() * 256.0F) / 360.0F)));
|
||||
|
||||
return spawnPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer getPlayerInfoPacket(final Player player, final UUID uuid) {
|
||||
final GameProfile profile = this.getCopyProfile(player, uuid);
|
||||
final PacketContainer playerInfoPacket = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
||||
final StructureModifier<EnumWrappers.PlayerInfoAction> action = playerInfoPacket.getPlayerInfoAction();
|
||||
final StructureModifier<List<PlayerInfoData>> infoData = playerInfoPacket.getPlayerInfoDataLists();
|
||||
|
||||
final List<PlayerInfoData> playerInfoData = new ArrayList<>();
|
||||
|
||||
playerInfoData.add(new PlayerInfoData(WrappedGameProfile
|
||||
.fromHandle(profile),
|
||||
0,
|
||||
EnumWrappers.NativeGameMode.fromBukkit(GameMode.CREATIVE),
|
||||
WrappedChatComponent.fromText(profile.getName())));
|
||||
|
||||
action.write(0, EnumWrappers.PlayerInfoAction.ADD_PLAYER);
|
||||
infoData.write(0, playerInfoData);
|
||||
|
||||
return playerInfoPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer getRemovePacket(final Player player, final UUID uuid, final int entityId) {
|
||||
final PacketContainer playerPacket = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
||||
final StructureModifier<EnumWrappers.PlayerInfoAction> action = playerPacket.getPlayerInfoAction();
|
||||
final StructureModifier<List<PlayerInfoData>> infoData = playerPacket.getPlayerInfoDataLists();
|
||||
|
||||
final List<PlayerInfoData> playerInfoData = new ArrayList<>();
|
||||
|
||||
final GameProfile profile = this.getCopyProfile(player, uuid);
|
||||
|
||||
playerInfoData.add(new PlayerInfoData(WrappedGameProfile
|
||||
.fromHandle(profile),
|
||||
0,
|
||||
EnumWrappers.NativeGameMode.fromBukkit(GameMode.CREATIVE),
|
||||
WrappedChatComponent.fromText("")));
|
||||
|
||||
action.write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
|
||||
infoData.write(0, playerInfoData);
|
||||
|
||||
return playerPacket;
|
||||
}
|
||||
|
||||
private GameProfile getCopyProfile(final Player player, final UUID uuid) {
|
||||
final GameProfile playerProfile = ((CraftPlayer) player).getProfile();
|
||||
final GameProfile profile = new GameProfile(
|
||||
uuid,
|
||||
player.getDisplayName()
|
||||
);
|
||||
|
||||
profile.getProperties().removeAll("textures");
|
||||
Property textureProperty = playerProfile.getProperties().get("textures").iterator().next();
|
||||
String texture = textureProperty.getValue();
|
||||
String signature = textureProperty.getSignature();
|
||||
profile.getProperties().put("textures", new Property("textures", texture, signature));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
}
|
||||
23
1.18/build.gradle.kts
Normal file
23
1.18/build.gradle.kts
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id("java")
|
||||
}
|
||||
|
||||
//group = "io.github.fisher2911"
|
||||
//version = "1.7.1"
|
||||
//description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.dmulloy2.net/repository/public/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":nms"))
|
||||
compileOnly("com.mojang:authlib:1.5.25")
|
||||
compileOnly("org.spigotmc:spigot:1.18-R0.1-SNAPSHOT")
|
||||
compileOnly("org.jetbrains:annotations:22.0.0")
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
|
||||
public class DestroyPacket_1_18_R1 implements DestroyPacket {
|
||||
|
||||
@Override
|
||||
public PacketContainer get(final int entityId) {
|
||||
final PacketContainer destroyPacket = new PacketContainer(
|
||||
PacketType.Play.Server.ENTITY_DESTROY);
|
||||
destroyPacket.getModifier().write(0, new IntArrayList(new int[]{entityId}));
|
||||
|
||||
return destroyPacket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerPackets_1_18_R1 implements PlayerPackets {
|
||||
|
||||
@Override
|
||||
public PacketContainer getSpawnPacket(final Location location, UUID uuid, final int entityId) {
|
||||
final PacketContainer spawnPacket = new PacketContainer(PacketType.Play.Server.NAMED_ENTITY_SPAWN);
|
||||
spawnPacket.getUUIDs().write(0, uuid);
|
||||
spawnPacket.getIntegers().write(0, entityId);
|
||||
spawnPacket.getDoubles().
|
||||
write(0, location.getX()).
|
||||
write(1, location.getY()).
|
||||
write(2, location.getZ());
|
||||
spawnPacket.getBytes().write(0, (byte)(((location.getYaw() * 256.0F) / 360.0F)));
|
||||
|
||||
return spawnPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer getPlayerInfoPacket(final Player player, final UUID uuid) {
|
||||
final GameProfile profile = this.getCopyProfile(player, uuid);
|
||||
final PacketContainer playerInfoPacket = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
||||
final StructureModifier<EnumWrappers.PlayerInfoAction> action = playerInfoPacket.getPlayerInfoAction();
|
||||
final StructureModifier<List<PlayerInfoData>> infoData = playerInfoPacket.getPlayerInfoDataLists();
|
||||
|
||||
final List<PlayerInfoData> playerInfoData = new ArrayList<>();
|
||||
|
||||
playerInfoData.add(new PlayerInfoData(WrappedGameProfile
|
||||
.fromHandle(profile),
|
||||
0,
|
||||
EnumWrappers.NativeGameMode.fromBukkit(GameMode.CREATIVE),
|
||||
WrappedChatComponent.fromText(profile.getName())));
|
||||
|
||||
action.write(0, EnumWrappers.PlayerInfoAction.ADD_PLAYER);
|
||||
infoData.write(0, playerInfoData);
|
||||
|
||||
return playerInfoPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer getRemovePacket(final Player player, final UUID uuid, final int entityId) {
|
||||
final PacketContainer playerPacket = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
||||
final StructureModifier<EnumWrappers.PlayerInfoAction> action = playerPacket.getPlayerInfoAction();
|
||||
final StructureModifier<List<PlayerInfoData>> infoData = playerPacket.getPlayerInfoDataLists();
|
||||
|
||||
final List<PlayerInfoData> playerInfoData = new ArrayList<>();
|
||||
|
||||
final GameProfile profile = this.getCopyProfile(player, uuid);
|
||||
|
||||
playerInfoData.add(new PlayerInfoData(WrappedGameProfile
|
||||
.fromHandle(profile),
|
||||
0,
|
||||
EnumWrappers.NativeGameMode.fromBukkit(GameMode.CREATIVE),
|
||||
WrappedChatComponent.fromText("")));
|
||||
|
||||
action.write(0, EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
|
||||
infoData.write(0, playerInfoData);
|
||||
|
||||
return playerPacket;
|
||||
}
|
||||
|
||||
private GameProfile getCopyProfile(final Player player, final UUID uuid) {
|
||||
final GameProfile playerProfile = ((CraftPlayer) player).getProfile();
|
||||
final GameProfile profile = new GameProfile(
|
||||
uuid,
|
||||
player.getDisplayName()
|
||||
);
|
||||
|
||||
profile.getProperties().removeAll("textures");
|
||||
Property textureProperty = playerProfile.getProperties().get("textures").iterator().next();
|
||||
String texture = textureProperty.getValue();
|
||||
String signature = textureProperty.getSignature();
|
||||
profile.getProperties().put("textures", new Property("textures", texture, signature));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
}
|
||||
11
README.md
11
README.md
@@ -6,16 +6,19 @@
|
||||
## Table of Contents
|
||||
- [Description](#description)
|
||||
- [Installation](#installation)
|
||||
- [Contact Information](#contact-information)
|
||||
- [Download](#download)
|
||||
|
||||
### Description
|
||||
|
||||
HMCCosmetics is a free, open source cosmetics plugin which allows you to easily give players backpack and hat type cosmetics.
|
||||
|
||||
HMCCosmetics is an intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.
|
||||
|
||||
### Requirements
|
||||
|
||||
- Server running PaperMC (or a fork of PaperMC)
|
||||
- ProtocolLib
|
||||
|
||||
### Download
|
||||
|
||||
If you would like to support the development of our plugin, please purchase it on [Polymart](https://polymart.org/resource/hmccosmetics.1879)
|
||||
|
||||
|
||||
|
||||
|
||||
51
build.gradle
51
build.gradle
@@ -1,51 +0,0 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '6.1.0'
|
||||
}
|
||||
|
||||
group 'io.github.fisher2911'
|
||||
version '1.0.0'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url = 'https://papermc.io/repo/repository/maven-public/' }
|
||||
maven { url = 'https://repo.mattstudios.me/artifactory/public/' }
|
||||
maven { url = 'https://jitpack.io' }
|
||||
maven { url = 'https://repo.leonardobishop.com/releases/' }
|
||||
maven { url = 'https://repo.dmulloy2.net/repository/public/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
compileOnly 'io.papermc.paper:paper:1.17.1-R0.1-SNAPSHOT'
|
||||
compileOnly 'org.jetbrains:annotations:22.0.0'
|
||||
compileOnly 'com.comphenix.protocol:ProtocolLib:4.7.0'
|
||||
compileOnly 'net.kyori:adventure-api:4.9.3'
|
||||
implementation 'net.kyori:adventure-text-minimessage:4.2.0-SNAPSHOT'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.0.0'
|
||||
implementation 'dev.triumphteam:triumph-gui:3.0.3'
|
||||
implementation 'me.mattstudios.utils:matt-framework:1.4.6'
|
||||
implementation 'org.spongepowered:configurate-yaml:4.1.2'
|
||||
implementation 'org.bstats:bstats-bukkit:2.2.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate 'dev.triumphteam.gui', 'io.github.fisher2911.hmccosmetics.gui'
|
||||
relocate 'me.mattstudios.mf', 'io.github.fisher2911.hmccosmetics.mf'
|
||||
relocate 'net.kyori.adventure.text.minimessage', 'io.github.fisher2911.hmccosmetics.adventure.minimessage'
|
||||
relocate 'net.kyori.adventure.platform', 'io.github.fisher2911.hmccosmetics.adventure.platform'
|
||||
relocate 'org.spongepowered.configurate', 'io.github.fisher2911.hmccosmetics.configurate'
|
||||
relocate 'org.bstats', 'io.github.fisher2911.hmccosmetics.bstats'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveBaseName.set('HMCCosmetics')
|
||||
archiveClassifier.set('')
|
||||
archiveVersion.set('')
|
||||
}
|
||||
112
build.gradle.kts
Normal file
112
build.gradle.kts
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
//import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
|
||||
//
|
||||
plugins {
|
||||
id("java")
|
||||
}
|
||||
// id("com.github.johnrengelman.shadow") version "7.1.1"
|
||||
// id("net.minecrell.plugin-yml.bukkit") version "0.5.1"
|
||||
//}
|
||||
//
|
||||
//group = "io.github.fisher2911"
|
||||
//version = "1.7.1"
|
||||
//description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
|
||||
//
|
||||
//repositories {
|
||||
// mavenCentral()
|
||||
// maven("https://papermc.io/repo/repository/maven-public/")
|
||||
// maven("https://repo.mattstudios.me/artifactory/public/")
|
||||
// maven("https://jitpack.io")
|
||||
// maven("https://repo.dmulloy2.net/repository/public/")
|
||||
// maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
// maven("https://mvnrepository.com/artifact/com.zaxxer/HikariCP")
|
||||
// maven("https://repo.jeff-media.de/maven2/")
|
||||
// maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
//}
|
||||
//
|
||||
//dependencies {
|
||||
// compileOnly("com.mojang:authlib:1.5.25")
|
||||
// compileOnly("org.spigotmc:spigot:1.17-R0.1-SNAPSHOT")
|
||||
// compileOnly("org.jetbrains:annotations:22.0.0")
|
||||
// compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0")
|
||||
// compileOnly("me.clip:placeholderapi:2.11.1")
|
||||
// compileOnly("com.github.oraxen:oraxen:-SNAPSHOT")
|
||||
// compileOnly("com.github.LoneDev6:API-ItemsAdder:2.5.4")
|
||||
// implementation("net.kyori:adventure-api:4.9.3")
|
||||
// implementation("net.kyori:adventure-text-minimessage:4.10.0-SNAPSHOT")
|
||||
// implementation("net.kyori:adventure-platform-bukkit:4.0.1")
|
||||
// implementation("dev.triumphteam:triumph-gui:3.1.1")
|
||||
// implementation("me.mattstudios.utils:matt-framework:1.4.6")
|
||||
// implementation("org.spongepowered:configurate-yaml:4.1.2")
|
||||
// implementation("org.bstats:bstats-bukkit:2.2.1")
|
||||
// implementation("com.zaxxer:HikariCP:5.0.0")
|
||||
// implementation("com.j256.ormlite:ormlite-jdbc:6.1")
|
||||
// implementation("com.j256.ormlite:ormlite-core:6.1")
|
||||
//}
|
||||
//
|
||||
//tasks {
|
||||
// build {
|
||||
// dependsOn(shadowJar)
|
||||
// }
|
||||
//
|
||||
// compileJava {
|
||||
// options.encoding = Charsets.UTF_8.name()
|
||||
// options.release.set(16)
|
||||
// }
|
||||
//
|
||||
// shadowJar {
|
||||
// relocate("dev.triumphteam.gui", "io.github.fisher2911.hmccosmetics.gui")
|
||||
// relocate("me.mattstudios.mf", "io.github.fisher2911.hmccosmetics.mf")
|
||||
// relocate("net.kyori.adventure.text.minimessage", "io.github.fisher2911.hmccosmetics.adventure.minimessage")
|
||||
// relocate("net.kyori.adventure.platform", "io.github.fisher2911.hmccosmetics.adventure.platform")
|
||||
// relocate("org.spongepowered.configurate", "io.github.fisher2911.hmccosmetics.configurate")
|
||||
// relocate("org.bstats", "io.github.fisher2911.hmccosmetics.bstats")
|
||||
// relocate("com.zaxxer.hikaricp", "io.github.fisher2911.hmccosmetics.hikaricp")
|
||||
// relocate("com.j256.ormlite", "io.github.fisher2911.hmccosmetics.ormlite")
|
||||
// archiveFileName.set("HMCCosmetics.jar")
|
||||
// }
|
||||
//
|
||||
// javadoc {
|
||||
// options.encoding = Charsets.UTF_8.name()
|
||||
// }
|
||||
//
|
||||
// processResources {
|
||||
// filteringCharset = Charsets.UTF_8.name()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//java {
|
||||
// toolchain.languageVersion.set(JavaLanguageVersion.of(16))
|
||||
//}
|
||||
//
|
||||
//bukkit {
|
||||
// load = BukkitPluginDescription.PluginLoadOrder.STARTUP
|
||||
// main = "io.github.fisher2911.hmccosmetics.HMCCosmetics"
|
||||
// apiVersion = "1.17"
|
||||
// name = "HMCCosmetics"
|
||||
// authors = listOf("MasterOfTheFish")
|
||||
// softDepend = listOf("Multiverse", "PlaceholderAPI", "Oraxen", "ItemsAdder")
|
||||
// depend = listOf("ProtocolLib")
|
||||
// permissions {
|
||||
// register("hmccosmetics.cmd.default") {
|
||||
// default = BukkitPluginDescription.Permission.Default.OP
|
||||
// description = "Permission to execute the default command."
|
||||
// }
|
||||
// register("hmccosmetics.cmd.dye") {
|
||||
// default = BukkitPluginDescription.Permission.Default.OP
|
||||
// description = "Permission to dye armor."
|
||||
// }
|
||||
// register("hmccosmetics.cmd.reload") {
|
||||
// default = BukkitPluginDescription.Permission.Default.OP
|
||||
// description = "Permission to use the reload command."
|
||||
// }
|
||||
// register("hmccosmetics.cmd.set") {
|
||||
// default = BukkitPluginDescription.Permission.Default.OP
|
||||
// description = "Permission to set other users' cosmetics."
|
||||
// }
|
||||
// register("hmccosmetics.cmd.wardrobe") {
|
||||
// default = BukkitPluginDescription.Permission.Default.OP
|
||||
// description = "Permission to view the wardrobe"
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
122
common/build.gradle.kts
Normal file
122
common/build.gradle.kts
Normal file
@@ -0,0 +1,122 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("com.github.johnrengelman.shadow") version "7.1.1"
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.5.1"
|
||||
}
|
||||
|
||||
group = "io.github.fisher2911"
|
||||
version = "1.7.1"
|
||||
description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://repo.mattstudios.me/artifactory/public/")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.dmulloy2.net/repository/public/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
maven("https://mvnrepository.com/artifact/com.zaxxer/HikariCP")
|
||||
maven("https://repo.jeff-media.de/maven2/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":1.17"))
|
||||
implementation(project(":1.18"))
|
||||
implementation(project(":nms"))
|
||||
compileOnly("com.mojang:authlib:1.5.25")
|
||||
compileOnly("org.spigotmc:spigot:1.17-R0.1-SNAPSHOT")
|
||||
compileOnly("org.jetbrains:annotations:22.0.0")
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0")
|
||||
compileOnly("me.clip:placeholderapi:2.11.1")
|
||||
compileOnly("com.github.oraxen:oraxen:-SNAPSHOT")
|
||||
compileOnly("com.github.LoneDev6:API-ItemsAdder:2.5.4")
|
||||
implementation("net.kyori:adventure-api:4.9.3")
|
||||
implementation("net.kyori:adventure-text-minimessage:4.10.0-SNAPSHOT")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.0.1")
|
||||
implementation("dev.triumphteam:triumph-gui:3.1.1")
|
||||
implementation("me.mattstudios.utils:matt-framework:1.4.6")
|
||||
implementation("org.spongepowered:configurate-yaml:4.1.2")
|
||||
implementation("org.bstats:bstats-bukkit:2.2.1")
|
||||
implementation("com.zaxxer:HikariCP:5.0.0")
|
||||
implementation("com.j256.ormlite:ormlite-jdbc:6.1")
|
||||
implementation("com.j256.ormlite:ormlite-core:6.1")
|
||||
}
|
||||
|
||||
tasks {
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
options.release.set(16)
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate("dev.triumphteam.gui", "io.github.fisher2911.hmccosmetics.gui")
|
||||
relocate("me.mattstudios.mf", "io.github.fisher2911.hmccosmetics.mf")
|
||||
relocate("net.kyori.adventure.text.minimessage", "io.github.fisher2911.hmccosmetics.adventure.minimessage")
|
||||
relocate("net.kyori.adventure.platform", "io.github.fisher2911.hmccosmetics.adventure.platform")
|
||||
relocate("org.spongepowered.configurate", "io.github.fisher2911.hmccosmetics.configurate")
|
||||
relocate("org.bstats", "io.github.fisher2911.hmccosmetics.bstats")
|
||||
relocate("com.zaxxer.hikaricp", "io.github.fisher2911.hmccosmetics.hikaricp")
|
||||
relocate("com.j256.ormlite", "io.github.fisher2911.hmccosmetics.ormlite")
|
||||
archiveFileName.set("HMCCosmetics.jar")
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
}
|
||||
|
||||
processResources {
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
filteringCharset = Charsets.UTF_8.name()
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(16))
|
||||
}
|
||||
|
||||
bukkit {
|
||||
load = BukkitPluginDescription.PluginLoadOrder.STARTUP
|
||||
main = "io.github.fisher2911.hmccosmetics.HMCCosmetics"
|
||||
apiVersion = "1.17"
|
||||
name = "HMCCosmetics"
|
||||
authors = listOf("MasterOfTheFish")
|
||||
softDepend = listOf("Multiverse", "PlaceholderAPI", "Oraxen", "ItemsAdder")
|
||||
depend = listOf("ProtocolLib")
|
||||
permissions {
|
||||
register("hmccosmetics.cmd.default") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to execute the default command."
|
||||
}
|
||||
register("hmccosmetics.cmd.dye") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to dye armor."
|
||||
}
|
||||
register("hmccosmetics.cmd.reload") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to use the reload command."
|
||||
}
|
||||
register("hmccosmetics.cmd.set") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to set other users' cosmetics."
|
||||
}
|
||||
register("hmccosmetics.cmd.wardrobe.portable") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to use a portable wardrobe"
|
||||
}
|
||||
register("hmccosmetics.cmd.wardrobe") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to view the wardrobe"
|
||||
}
|
||||
register("hmccosmetics.cmd.wardrobe.other") {
|
||||
default = BukkitPluginDescription.Permission.Default.OP
|
||||
description = "Permission to open another player's wardrobe"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package io.github.fisher2911.hmccosmetics;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import io.github.fisher2911.hmccosmetics.command.CosmeticsCommand;
|
||||
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
|
||||
import io.github.fisher2911.hmccosmetics.config.Settings;
|
||||
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
|
||||
import io.github.fisher2911.hmccosmetics.database.Database;
|
||||
import io.github.fisher2911.hmccosmetics.database.DatabaseFactory;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.gui.CosmeticsMenu;
|
||||
import io.github.fisher2911.hmccosmetics.hook.HookManager;
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.ItemsAdderHook;
|
||||
import io.github.fisher2911.hmccosmetics.listener.ClickListener;
|
||||
import io.github.fisher2911.hmccosmetics.listener.CosmeticFixListener;
|
||||
import io.github.fisher2911.hmccosmetics.listener.JoinListener;
|
||||
import io.github.fisher2911.hmccosmetics.listener.PlayerShiftListener;
|
||||
import io.github.fisher2911.hmccosmetics.listener.RespawnListener;
|
||||
import io.github.fisher2911.hmccosmetics.listener.TeleportListener;
|
||||
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
|
||||
import io.github.fisher2911.hmccosmetics.message.Messages;
|
||||
import io.github.fisher2911.hmccosmetics.message.Translation;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.mattstudios.mf.base.CommandManager;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class HMCCosmetics extends JavaPlugin {
|
||||
|
||||
public static final Path PLUGIN_FOLDER = Paths.get("plugins", "HMCCosmetics");
|
||||
|
||||
private ProtocolManager protocolManager;
|
||||
private Settings settings;
|
||||
private UserManager userManager;
|
||||
private CosmeticManager cosmeticManager;
|
||||
private MessageHandler messageHandler;
|
||||
private CosmeticsMenu cosmeticsMenu;
|
||||
private CommandManager commandManager;
|
||||
private Database database;
|
||||
|
||||
private BukkitTask saveTask;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
final int pluginId = 13873;
|
||||
final Metrics metrics = new Metrics(this, pluginId);
|
||||
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
this.settings = new Settings(this);
|
||||
this.messageHandler = new MessageHandler(this);
|
||||
this.userManager = new UserManager(this);
|
||||
this.cosmeticManager = new CosmeticManager(new HashMap<>());
|
||||
this.cosmeticsMenu = new CosmeticsMenu(this);
|
||||
|
||||
this.userManager.startTeleportTask();
|
||||
|
||||
try {
|
||||
this.database = DatabaseFactory.create(this);
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
this.registerCommands();
|
||||
this.registerListeners();
|
||||
|
||||
if (!HookManager.getInstance().isEnabled(ItemsAdderHook.class)) {
|
||||
this.load();
|
||||
}
|
||||
|
||||
HookManager.getInstance().init();
|
||||
|
||||
this.saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
this,
|
||||
() -> Threads.getInstance().execute(
|
||||
() -> this.database.saveAll()
|
||||
),
|
||||
20 * 60,
|
||||
20 * 60
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.saveTask.cancel();
|
||||
this.database.saveAll();
|
||||
this.messageHandler.close();
|
||||
this.userManager.cancelTeleportTask();
|
||||
this.userManager.removeAll();
|
||||
Threads.getInstance().onDisable();
|
||||
this.database.close();
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
List.of(
|
||||
new JoinListener(this),
|
||||
new ClickListener(this),
|
||||
new TeleportListener(this),
|
||||
new RespawnListener(this),
|
||||
new CosmeticFixListener(this),
|
||||
new PlayerShiftListener(this)
|
||||
).
|
||||
forEach(
|
||||
listener -> this.getServer().getPluginManager()
|
||||
.registerEvents(listener, this)
|
||||
);
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
this.commandManager = new CommandManager(this, true);
|
||||
this.commandManager.getMessageHandler().register(
|
||||
"cmd.no.console", player ->
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.MUST_BE_PLAYER
|
||||
)
|
||||
);
|
||||
this.commandManager.getCompletionHandler().register("#types",
|
||||
resolver ->
|
||||
Arrays.stream(ArmorItem.Type.
|
||||
values()).
|
||||
map(ArmorItem.Type::toString).
|
||||
collect(Collectors.toList())
|
||||
);
|
||||
this.commandManager.getCompletionHandler().register("#ids",
|
||||
resolver ->
|
||||
this.cosmeticManager.getAll().stream().map(ArmorItem::getId)
|
||||
.collect(Collectors.toList()));
|
||||
this.commandManager.register(new CosmeticsCommand(this));
|
||||
}
|
||||
|
||||
public void load() {
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this,
|
||||
() -> {
|
||||
this.settings.load();
|
||||
this.messageHandler.load();
|
||||
this.cosmeticsMenu.load();
|
||||
Translation.getInstance().load();
|
||||
this.database.load();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this,
|
||||
() -> {
|
||||
this.settings.load();
|
||||
this.messageHandler.load();
|
||||
this.cosmeticsMenu.reload();
|
||||
Translation.getInstance().load();
|
||||
});
|
||||
}
|
||||
|
||||
public Settings getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public MessageHandler getMessageHandler() {
|
||||
return messageHandler;
|
||||
}
|
||||
|
||||
public UserManager getUserManager() {
|
||||
return userManager;
|
||||
}
|
||||
|
||||
public CosmeticManager getCosmeticManager() {
|
||||
return cosmeticManager;
|
||||
}
|
||||
|
||||
public CosmeticsMenu getCosmeticsMenu() {
|
||||
return cosmeticsMenu;
|
||||
}
|
||||
|
||||
public ProtocolManager getProtocolManager() {
|
||||
return protocolManager;
|
||||
}
|
||||
|
||||
public Database getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package io.github.fisher2911.hmccosmetics.api;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import java.util.ArrayList;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Wrapper for ArmorItem used internally for convenience and safety
|
||||
*/
|
||||
public class CosmeticItem {
|
||||
|
||||
private final ArmorItem armorItem;
|
||||
|
||||
public CosmeticItem(final ArmorItem armorItem) {
|
||||
this.armorItem = armorItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemStack the {@link org.bukkit.inventory.ItemStack} display item
|
||||
* @param id the id of the item
|
||||
* @param type the cosmetic item type
|
||||
* @param dyeable whether the item can be dyed
|
||||
* @param rgb from Bukkit's {@link Color#asRGB()}
|
||||
*/
|
||||
|
||||
public CosmeticItem(final ItemStack itemStack, final String id, final ArmorItem.Type type,
|
||||
final boolean dyeable, final int rgb) {
|
||||
this.armorItem = new ArmorItem(itemStack, id, new ArrayList<>(), "", type, dyeable, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material the {@link org.bukkit.Material} display item
|
||||
* @param id the id of the item
|
||||
* @param type the cosmetic item type
|
||||
* @param dyeable whether the item can be dyed
|
||||
* @param rgb from Bukkit's {@link Color#asRGB()}
|
||||
*/
|
||||
|
||||
public CosmeticItem(final Material material, final String id, final ArmorItem.Type type,
|
||||
final boolean dyeable, final int rgb) {
|
||||
this.armorItem = new ArmorItem(material, id, new ArrayList<>(), "", type, dyeable, rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemStack the {@link org.bukkit.inventory.ItemStack} display item
|
||||
* @param id the id of the item
|
||||
* @param type the cosmetic item type
|
||||
*/
|
||||
|
||||
public CosmeticItem(final ItemStack itemStack, final String id, final ArmorItem.Type type) {
|
||||
this(itemStack, id, type, false, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material the {@link org.bukkit.Material} display item
|
||||
* @param id the id of the item
|
||||
* @param type the cosmetic item type
|
||||
*/
|
||||
|
||||
public CosmeticItem(final Material material, final String id, final ArmorItem.Type type) {
|
||||
this(material, id, type, false, -1);
|
||||
}
|
||||
|
||||
public ItemStack getColored() {
|
||||
return this.armorItem.getColored();
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return this.armorItem.getItemStack();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.armorItem.getId();
|
||||
}
|
||||
|
||||
public ArmorItem.Type getType() {
|
||||
return this.armorItem.getType();
|
||||
}
|
||||
|
||||
public boolean isDyeable() {
|
||||
return this.armorItem.isDyeable();
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return this.armorItem.getDye();
|
||||
}
|
||||
|
||||
public ArmorItem getArmorItem() {
|
||||
return this.armorItem;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package io.github.fisher2911.hmccosmetics.api;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HMCCosmeticsAPI {
|
||||
|
||||
private static final HMCCosmetics plugin;
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This will attempt to get the {@link io.github.fisher2911.hmccosmetics.api.CosmeticItem} that
|
||||
* the user is wearing. It returns an empty {@link io.github.fisher2911.hmccosmetics.api.CosmeticItem}
|
||||
* if the user is not found, or if the user is not wearing a cosmetic
|
||||
*
|
||||
* @param uuid the uuid of the user
|
||||
* @param type the type of cosmetic being retrieved
|
||||
* @return the current cosmetic of the player
|
||||
*/
|
||||
public static CosmeticItem getUserCurrentItem(final UUID uuid, final ArmorItem.Type type) {
|
||||
final Optional<User> userOptional = plugin.getUserManager().get(uuid);
|
||||
if (userOptional.isEmpty()) {
|
||||
return new CosmeticItem(ArmorItem.empty(type));
|
||||
}
|
||||
return new CosmeticItem(userOptional.get().getPlayerArmor().getItem(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uuid the uuid of the user whose cosmetic is being set
|
||||
* @param cosmeticItem the cosmetic being set
|
||||
* @return true if the cosmetic was set, or else false
|
||||
*/
|
||||
public static boolean setCosmeticItem(final UUID uuid, final CosmeticItem cosmeticItem) {
|
||||
final UserManager userManager = plugin.getUserManager();
|
||||
final Optional<User> userOptional = userManager.get(uuid);
|
||||
if (userOptional.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
userManager.setItem(userOptional.get(), cosmeticItem.getArmorItem());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id of the cosmetic item being retrieved
|
||||
* @return null if the cosmetic was not found, or a copy of the cosmetic item
|
||||
*/
|
||||
|
||||
@Nullable
|
||||
public static CosmeticItem getCosmeticFromId(final String id) {
|
||||
final ArmorItem armorItem = plugin.getCosmeticManager().getArmorItem(id);
|
||||
if (armorItem == null) {
|
||||
return null;
|
||||
}
|
||||
return new CosmeticItem(new ArmorItem(armorItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uuid the uuid of the user whose armor stand id is being retrieved
|
||||
* @return the armor stand id, or -1 if the user is not found
|
||||
*/
|
||||
|
||||
public static int getUserArmorStandId(final UUID uuid) {
|
||||
final Optional<User> userOptional = plugin.getUserManager().get(uuid);
|
||||
if (userOptional.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
return userOptional.get().getArmorStandId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.github.fisher2911.hmccosmetics.api.event;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
|
||||
/**
|
||||
* Called when a user changes their equipped cosmetic
|
||||
*/
|
||||
public class CosmeticChangeEvent extends CosmeticItemEvent {
|
||||
|
||||
private final User user;
|
||||
private CosmeticItem removed;
|
||||
|
||||
public CosmeticChangeEvent(final CosmeticItem cosmeticItem, final CosmeticItem removed,
|
||||
final User user) {
|
||||
super(cosmeticItem);
|
||||
this.removed = removed;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public CosmeticItem getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void setRemoved(final CosmeticItem removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.github.fisher2911.hmccosmetics.api.event;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public abstract class CosmeticItemEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private CosmeticItem cosmeticItem;
|
||||
private boolean cancelled;
|
||||
|
||||
public CosmeticItemEvent(final CosmeticItem cosmeticItem) {
|
||||
this.cosmeticItem = cosmeticItem;
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
public CosmeticItem getCosmeticItem() {
|
||||
return this.cosmeticItem;
|
||||
}
|
||||
|
||||
public void setCosmeticItem(final CosmeticItem cosmeticItem) {
|
||||
this.cosmeticItem = cosmeticItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(final boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package io.github.fisher2911.hmccosmetics.command;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.config.Settings;
|
||||
import io.github.fisher2911.hmccosmetics.config.WardrobeSettings;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.gui.CosmeticsMenu;
|
||||
import io.github.fisher2911.hmccosmetics.message.Message;
|
||||
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
|
||||
import io.github.fisher2911.hmccosmetics.message.Messages;
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
import io.github.fisher2911.hmccosmetics.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import me.mattstudios.mf.annotations.Command;
|
||||
import me.mattstudios.mf.annotations.Completion;
|
||||
import me.mattstudios.mf.annotations.Default;
|
||||
import me.mattstudios.mf.annotations.Permission;
|
||||
import me.mattstudios.mf.annotations.SubCommand;
|
||||
import me.mattstudios.mf.base.CommandBase;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@Command("cosmetics")
|
||||
public class CosmeticsCommand extends CommandBase {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UserManager userManager;
|
||||
private final MessageHandler messageHandler;
|
||||
private final CosmeticsMenu cosmeticsMenu;
|
||||
private final Settings settings;
|
||||
|
||||
public CosmeticsCommand(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
this.messageHandler = this.plugin.getMessageHandler();
|
||||
this.cosmeticsMenu = this.plugin.getCosmeticsMenu();
|
||||
this.settings = this.plugin.getSettings();
|
||||
}
|
||||
|
||||
@Default
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.DEFAULT_COMMAND)
|
||||
public void defaultCommand(final Player player) {
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
if (optionalUser.isEmpty()) {
|
||||
this.cosmeticsMenu.openDefault(player);
|
||||
return;
|
||||
}
|
||||
final User user = optionalUser.get();
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
if (wardrobe.isActive() &&
|
||||
!this.settings.getWardrobeSettings().inDistanceOfWardrobe(wardrobe.getCurrentLocation(), player.getLocation())) {
|
||||
wardrobe.setActive(false);
|
||||
wardrobe.despawnFakePlayer(player);
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.CLOSED_WARDROBE
|
||||
);
|
||||
}
|
||||
this.cosmeticsMenu.openDefault(player);
|
||||
}
|
||||
|
||||
@SubCommand("reload")
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.RELOAD_COMMAND)
|
||||
public void reloadCommand(final CommandSender sender) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
this.plugin,
|
||||
() -> {
|
||||
this.plugin.reload();
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.RELOADED
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@SubCommand("dye")
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.DYE_COMMAND)
|
||||
public void dyeArmor(final Player player, @Completion("#types") String typeString,
|
||||
final @me.mattstudios.mf.annotations.Optional String dyeColor) {
|
||||
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (optionalUser.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeString.toUpperCase());
|
||||
|
||||
final User user = optionalUser.get();
|
||||
|
||||
if (dyeColor == null) {
|
||||
this.cosmeticsMenu.openDyeSelectorGui(user, type);
|
||||
return;
|
||||
}
|
||||
|
||||
final ArmorItem armorItem = user.getPlayerArmor().getItem(type);
|
||||
|
||||
if (dyeColor != null) {
|
||||
this.setDyeColor(dyeColor, armorItem, player);
|
||||
}
|
||||
|
||||
this.userManager.setItem(user, armorItem);
|
||||
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.SET_DYE_COLOR,
|
||||
Map.of(Placeholder.ITEM, StringUtils.formatArmorItemType(typeString))
|
||||
);
|
||||
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.INVALID_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@SubCommand("help") // WORK IN PROGRESS (WIP)
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.HELP_COMMAND)
|
||||
public void helpCommand(final CommandSender sender) {
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.HELP_COMMAND
|
||||
);
|
||||
}
|
||||
|
||||
@SubCommand("add")
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.SET_COSMETIC_COMMAND)
|
||||
public void setCommand(
|
||||
final CommandSender sender,
|
||||
@Completion("#players") final Player player,
|
||||
@Completion("#ids") final String id,
|
||||
final @me.mattstudios.mf.annotations.Optional String dyeColor) {
|
||||
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (userOptional.isEmpty()) {
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.INVALID_USER
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final User user = userOptional.get();
|
||||
final ArmorItem armorItem = this.plugin.getCosmeticManager().getArmorItem(id);
|
||||
|
||||
if (armorItem == null) {
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.ITEM_NOT_FOUND
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dyeColor != null) {
|
||||
this.setDyeColor(dyeColor, armorItem, player);
|
||||
}
|
||||
|
||||
final Message setMessage = Messages.getSetMessage(armorItem.getType());
|
||||
final Message setOtherMessage = Messages.getSetOtherMessage(armorItem.getType());
|
||||
this.userManager.setItem(user, armorItem);
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
setMessage
|
||||
);
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
setOtherMessage,
|
||||
Map.of(Placeholder.PLAYER, player.getName(),
|
||||
Placeholder.TYPE, id)
|
||||
);
|
||||
}
|
||||
|
||||
@SubCommand("remove")
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.SET_COSMETIC_COMMAND)
|
||||
public void removeCommand(final CommandSender sender,
|
||||
@Completion("#players") final Player player, @Completion("#types") String typeString) {
|
||||
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (userOptional.isEmpty()) {
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.INVALID_USER
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final User user = userOptional.get();
|
||||
|
||||
try {
|
||||
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeString.toUpperCase());
|
||||
|
||||
final Message setOtherMessage = Messages.getSetOtherMessage(type);
|
||||
this.userManager.removeItem(user, type);
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
setOtherMessage,
|
||||
Map.of(Placeholder.PLAYER, player.getName(),
|
||||
Placeholder.TYPE, "none")
|
||||
);
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
this.messageHandler.sendMessage(player, Messages.INVALID_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
@SubCommand("wardrobe")
|
||||
@Permission(io.github.fisher2911.hmccosmetics.message.Permission.WARDROBE)
|
||||
public void openWardrobe(Player player, @me.mattstudios.mf.annotations.Optional final Player other) {
|
||||
if (other != null) {
|
||||
if (!player.hasPermission(io.github.fisher2911.hmccosmetics.message.Permission.OPEN_OTHER_WARDROBE)) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.NO_PERMISSION
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.OPENED_OTHER_WARDROBE,
|
||||
Map.of(Placeholder.PLAYER, other.getName())
|
||||
);
|
||||
player = other;
|
||||
}
|
||||
final Optional<User> optionalUser = this.plugin.getUserManager().get(player.getUniqueId());
|
||||
if (optionalUser.isEmpty()) return;
|
||||
|
||||
final User user = optionalUser.get();
|
||||
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
if (wardrobe.isActive()) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.WARDROBE_ALREADY_OPEN
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final WardrobeSettings settings = this.settings.getWardrobeSettings();
|
||||
|
||||
final boolean inDistanceOfStatic = settings.inDistanceOfStatic(player.getLocation());
|
||||
|
||||
if (!settings.isPortable() && !inDistanceOfStatic) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.NOT_NEAR_WARDROBE
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.isPortable() && !inDistanceOfStatic) {
|
||||
if (!player.hasPermission(io.github.fisher2911.hmccosmetics.message.Permission.PORTABLE_WARDROBE)) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.CANNOT_USE_PORTABLE_WARDROBE
|
||||
);
|
||||
return;
|
||||
}
|
||||
wardrobe.setCurrentLocation(null);
|
||||
}
|
||||
|
||||
wardrobe.setActive(true);
|
||||
|
||||
final Player finalPlayer = player;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
this.plugin,
|
||||
() -> wardrobe.spawnFakePlayer(finalPlayer)
|
||||
);
|
||||
|
||||
this.cosmeticsMenu.openDefault(player);
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.OPENED_WARDROBE
|
||||
);
|
||||
}
|
||||
|
||||
private void setDyeColor(final String dyeColor, final ArmorItem armorItem, final CommandSender sender) {
|
||||
try {
|
||||
final java.awt.Color awtColor = java.awt.Color.decode(dyeColor);
|
||||
Color color = Color.fromRGB(awtColor.getRed(), awtColor.getGreen(), awtColor.getBlue());
|
||||
armorItem.setDye(color.asRGB());
|
||||
} catch (final NumberFormatException exception) {
|
||||
this.messageHandler.sendMessage(
|
||||
sender,
|
||||
Messages.INVALID_COLOR,
|
||||
Map.of(Placeholder.ITEM, dyeColor)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.github.fisher2911.hmccosmetics.concurrent;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Threads {
|
||||
|
||||
private static final Threads INSTANCE;
|
||||
|
||||
static {
|
||||
INSTANCE = new Threads();
|
||||
}
|
||||
|
||||
private final ExecutorService service;
|
||||
|
||||
private Threads() {
|
||||
this.service = Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
public static Threads getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void execute(final Runnable runnable) {
|
||||
this.service.execute(runnable);
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
this.service.shutdownNow().forEach(Runnable::run);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import dev.triumphteam.gui.components.GuiAction;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.message.Message;
|
||||
import io.github.fisher2911.hmccosmetics.util.Utils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ActionSerializer implements TypeSerializer<GuiAction<InventoryClickEvent>> {
|
||||
|
||||
public static final ActionSerializer INSTANCE = new ActionSerializer();
|
||||
private static final HMCCosmetics plugin;
|
||||
|
||||
private static final String OPEN_MENU = "open-menu";
|
||||
private static final String SEND_MESSAGE = "send-message";
|
||||
private static final String SOUND = "sound";
|
||||
private static final String SOUND_NAME = "name";
|
||||
private static final String SOUND_VOLUME = "volume";
|
||||
private static final String SOUND_PITCH = "pitch";
|
||||
private static final String SOUND_CATEGORY = "category";
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
private ActionSerializer() {
|
||||
}
|
||||
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
|
||||
throws SerializationException {
|
||||
if (!source.hasChild(path)) {
|
||||
throw new SerializationException(
|
||||
"Required field " + Arrays.toString(path) + " was not present in node");
|
||||
}
|
||||
|
||||
return source.node(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiAction<InventoryClickEvent> deserialize(final Type type, final ConfigurationNode source) {
|
||||
final var children = source.childrenMap();
|
||||
final List<Consumer<InventoryClickEvent>> consumers = new ArrayList<>();
|
||||
for (final var entry : children.entrySet()) {
|
||||
final String clickType = entry.getKey().toString();
|
||||
if (clickType == null) continue;
|
||||
consumers.add(this.parseAction(entry.getValue(), clickType.toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
return event -> {
|
||||
for (final Consumer<InventoryClickEvent> consumer : consumers) {
|
||||
consumer.accept(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Consumer<InventoryClickEvent> parseAction(final ConfigurationNode node, final String clickType) {
|
||||
final ConfigurationNode openMenuNode = node.node(OPEN_MENU);
|
||||
final ConfigurationNode sendMessageNode = node.node(SEND_MESSAGE);
|
||||
final ConfigurationNode soundNode = node.node(SOUND);
|
||||
final ConfigurationNode soundNameNode = soundNode.node(SOUND_NAME);
|
||||
final ConfigurationNode volumeNode = soundNode.node(SOUND_VOLUME);
|
||||
final ConfigurationNode pitchNode = soundNode.node(SOUND_PITCH);
|
||||
final ConfigurationNode categoryNode = soundNode.node(SOUND_CATEGORY);
|
||||
|
||||
final String openMenu = openMenuNode.getString();
|
||||
final String sendMessage = sendMessageNode.getString();
|
||||
|
||||
final SoundData soundData;
|
||||
|
||||
final String soundName = soundNameNode.getString();
|
||||
final String category = categoryNode.getString();
|
||||
final int volume = volumeNode.getInt();
|
||||
final int pitch = pitchNode.getInt();
|
||||
if (soundName == null || category == null) {
|
||||
soundData = null;
|
||||
} else {
|
||||
soundData = new SoundData(
|
||||
soundName,
|
||||
EnumWrappers.SoundCategory.valueOf(category),
|
||||
volume,
|
||||
pitch
|
||||
);
|
||||
}
|
||||
|
||||
final ClickType click = Utils.stringToEnum(clickType, ClickType.class, ClickType.UNKNOWN);
|
||||
|
||||
return event -> {
|
||||
if (click != ClickType.UNKNOWN && event.getClick() != click) return;
|
||||
if (!(event.getWhoClicked() instanceof final Player player)) return;
|
||||
if (soundData != null) {
|
||||
soundData.play(player);
|
||||
}
|
||||
|
||||
if (sendMessage != null) plugin.getMessageHandler().sendMessage(
|
||||
player,
|
||||
new Message("", sendMessage)
|
||||
);
|
||||
if (openMenu != null) plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, @Nullable final GuiAction<InventoryClickEvent> obj, final ConfigurationNode node) throws SerializationException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
@ConfigSerializable
|
||||
public class CosmeticSettings {
|
||||
|
||||
private static final transient String COSMETIC_SETTINGS_PATH = "cosmetic-settings";
|
||||
private static final transient String REQUIRE_EMPTY_HELMET_PATH = "require-empty-helmet";
|
||||
private static final transient String REQUIRE_EMPTY_OFF_HAND_PATH = "require-empty-off-hand";
|
||||
private static final transient String LOOK_DOWN_PITCH_PATH = "look-down-backpack-remove";
|
||||
|
||||
private boolean requireEmptyHelmet;
|
||||
private boolean requireEmptyOffHand;
|
||||
private int lookDownPitch;
|
||||
|
||||
public void load(final FileConfiguration config) {
|
||||
this.requireEmptyHelmet = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_HELMET_PATH);
|
||||
this.requireEmptyOffHand = config.getBoolean(COSMETIC_SETTINGS_PATH + "." + REQUIRE_EMPTY_OFF_HAND_PATH);
|
||||
this.lookDownPitch = config.getInt(COSMETIC_SETTINGS_PATH + "." + LOOK_DOWN_PITCH_PATH);
|
||||
}
|
||||
|
||||
public boolean isRequireEmptyHelmet() {
|
||||
return requireEmptyHelmet;
|
||||
}
|
||||
|
||||
public boolean isRequireEmptyOffHand() {
|
||||
return requireEmptyOffHand;
|
||||
}
|
||||
|
||||
public int getLookDownPitch() {
|
||||
return lookDownPitch;
|
||||
}
|
||||
|
||||
public void setRequireEmptyHelmet(final boolean requireEmptyHelmet) {
|
||||
this.requireEmptyHelmet = requireEmptyHelmet;
|
||||
}
|
||||
|
||||
public void setRequireEmptyOffHand(final boolean requireEmptyOffHand) {
|
||||
this.requireEmptyOffHand = requireEmptyOffHand;
|
||||
}
|
||||
|
||||
public boolean requireEmpty(final EquipmentSlot slot) {
|
||||
return switch (slot) {
|
||||
case OFF_HAND -> this.isRequireEmptyOffHand();
|
||||
case HEAD -> this.isRequireEmptyHelmet();
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,66 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ColorItem;
|
||||
import io.github.fisher2911.hmccosmetics.gui.DyeSelectorGui;
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.bukkit.Color;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DyeGuiSerializer implements TypeSerializer<DyeSelectorGui> {
|
||||
|
||||
private static final HMCCosmetics plugin;
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
public static final DyeGuiSerializer INSTANCE = new DyeGuiSerializer();
|
||||
|
||||
private DyeGuiSerializer() {}
|
||||
|
||||
private static final HMCCosmetics plugin;
|
||||
private static final String TITLE = "title";
|
||||
private static final String ROWS = "rows";
|
||||
private static final String ITEMS = "items";
|
||||
private static final String COSMETICS_SLOTS = "cosmetics-slots";
|
||||
private static final String SET_COLOR = "set-color";
|
||||
private static final String RED = "red";
|
||||
private static final String GREEN = "green";
|
||||
private static final String BLUE = "blue";
|
||||
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
private DyeGuiSerializer() {
|
||||
}
|
||||
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
|
||||
throws SerializationException {
|
||||
if (!source.hasChild(path)) {
|
||||
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
|
||||
throw new SerializationException(
|
||||
"Required field " + Arrays.toString(path) + " was not present in node");
|
||||
}
|
||||
return source.node(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DyeSelectorGui deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
|
||||
public DyeSelectorGui deserialize(final Type type, final ConfigurationNode source)
|
||||
throws SerializationException {
|
||||
final ConfigurationNode titleNode = this.nonVirtualNode(source, TITLE);
|
||||
final ConfigurationNode rowsNode = this.nonVirtualNode(source, ROWS);
|
||||
final ConfigurationNode itemsNode = source.node(ITEMS);
|
||||
|
||||
final ConfigurationNode cosmeticSlotsNode = source.node(COSMETICS_SLOTS);
|
||||
|
||||
final Map<Integer, GuiItem> guiItemMap = new HashMap<>();
|
||||
|
||||
final var map = itemsNode.childrenMap();
|
||||
final var itemMap = itemsNode.childrenMap();
|
||||
final var cosmeticSlotsMap = cosmeticSlotsNode.childrenMap();
|
||||
|
||||
for (final var entry : map.entrySet()) {
|
||||
for (final var entry : itemMap.entrySet()) {
|
||||
if (!(entry.getKey() instanceof final Integer slot)) {
|
||||
continue;
|
||||
}
|
||||
@@ -78,19 +83,50 @@ public class DyeGuiSerializer implements TypeSerializer<DyeSelectorGui> {
|
||||
final int green = colorNode.node(GREEN).getInt();
|
||||
final int blue = colorNode.node(BLUE).getInt();
|
||||
|
||||
guiItemMap.put(slot, new ColorItem(guiItem.getItemStack(), Color.fromRGB(red, green, blue)));
|
||||
guiItemMap.put(slot,
|
||||
new ColorItem(guiItem.getItemStack(), Color.fromRGB(red, green, blue)));
|
||||
}
|
||||
|
||||
final BiMap<Integer, ArmorItem.Type> cosmeticSlots = HashBiMap.create();
|
||||
int selectedCosmetic = -1;
|
||||
for (final var entry : cosmeticSlotsMap.entrySet()) {
|
||||
if (!(entry.getKey() instanceof final Integer slot)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
selectedCosmetic = selectedCosmetic == -1 ? slot : selectedCosmetic;
|
||||
|
||||
final var node = entry.getValue();
|
||||
|
||||
final String typeStr = node.getString();
|
||||
|
||||
try {
|
||||
final ArmorItem.Type itemType = ArmorItem.Type.valueOf(typeStr);
|
||||
cosmeticSlots.put(slot, itemType);
|
||||
} catch (final IllegalArgumentException | NullPointerException exception) {
|
||||
plugin.getLogger().severe(typeStr + " is not a valid ArmorItem type in DyeGui!");
|
||||
}
|
||||
}
|
||||
|
||||
String title = titleNode.getString();
|
||||
|
||||
if (title == null) {
|
||||
title = "";
|
||||
}
|
||||
|
||||
return new DyeSelectorGui(
|
||||
plugin,
|
||||
Adventure.SERIALIZER.serialize(
|
||||
Adventure.MINI_MESSAGE.parse(titleNode.getString())),
|
||||
Adventure.MINI_MESSAGE.deserialize(title)),
|
||||
rowsNode.getInt(),
|
||||
guiItemMap);
|
||||
guiItemMap,
|
||||
cosmeticSlots,
|
||||
selectedCosmetic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, @Nullable final DyeSelectorGui obj, final ConfigurationNode node) throws SerializationException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,46 +4,47 @@ import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.gui.CosmeticGui;
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GuiSerializer implements TypeSerializer<CosmeticGui> {
|
||||
|
||||
public static final GuiSerializer INSTANCE = new GuiSerializer();
|
||||
private static final HMCCosmetics plugin;
|
||||
private static final String TITLE = "title";
|
||||
private static final String ROWS = "rows";
|
||||
private static final String ITEMS = "items";
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
public static final GuiSerializer INSTANCE = new GuiSerializer();
|
||||
private GuiSerializer() {
|
||||
}
|
||||
|
||||
private GuiSerializer() {}
|
||||
|
||||
private static final String TITLE = "title";
|
||||
private static final String ROWS = "rows";
|
||||
private static final String ITEMS = "items";
|
||||
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
|
||||
throws SerializationException {
|
||||
if (!source.hasChild(path)) {
|
||||
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
|
||||
throw new SerializationException(
|
||||
"Required field " + Arrays.toString(path) + " was not present in node");
|
||||
}
|
||||
return source.node(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CosmeticGui deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
|
||||
public CosmeticGui deserialize(final Type type, final ConfigurationNode source)
|
||||
throws SerializationException {
|
||||
final ConfigurationNode titleNode = this.nonVirtualNode(source, TITLE);
|
||||
final ConfigurationNode rowsNode = this.nonVirtualNode(source, ROWS);
|
||||
final ConfigurationNode itemsNode = source.node(ITEMS);
|
||||
|
||||
final var childrenMap = source.node(ITEMS).childrenMap();
|
||||
final var childrenMap = itemsNode.childrenMap();
|
||||
|
||||
final Map<Integer, GuiItem> guiItemMap = new HashMap<>();
|
||||
|
||||
@@ -60,9 +61,15 @@ public class GuiSerializer implements TypeSerializer<CosmeticGui> {
|
||||
guiItemMap.put(slot, guiItem);
|
||||
}
|
||||
|
||||
String title = titleNode.getString();
|
||||
|
||||
if (title == null) {
|
||||
title = "";
|
||||
}
|
||||
|
||||
return new CosmeticGui(plugin,
|
||||
Adventure.SERIALIZER.serialize(
|
||||
Adventure.MINI_MESSAGE.parse(titleNode.getString())),
|
||||
Adventure.MINI_MESSAGE.deserialize(title)),
|
||||
rowsNode.getInt(),
|
||||
guiItemMap);
|
||||
}
|
||||
@@ -71,4 +78,5 @@ public class GuiSerializer implements TypeSerializer<CosmeticGui> {
|
||||
public void serialize(final Type type, @Nullable final CosmeticGui obj, final ConfigurationNode node) throws SerializationException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +1,16 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import dev.triumphteam.gui.components.GuiAction;
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import io.github.fisher2911.hmccosmetics.hook.HookManager;
|
||||
import io.github.fisher2911.hmccosmetics.util.Keys;
|
||||
import io.github.fisher2911.hmccosmetics.util.StringUtils;
|
||||
import io.github.fisher2911.hmccosmetics.util.Utils;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ColorBuilder;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.SkullBuilder;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -33,11 +19,25 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
|
||||
public static final ItemSerializer INSTANCE = new ItemSerializer();
|
||||
|
||||
private static final HMCCosmetics plugin;
|
||||
private static final String MATERIAL = "material";
|
||||
private static final String AMOUNT = "amount";
|
||||
private static final String NAME = "name";
|
||||
@@ -56,23 +56,30 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
private static final String BLUE = "blue";
|
||||
private static final String PERMISSION = "permission";
|
||||
private static final String TYPE = "type";
|
||||
private static final String OPEN_MENU = "open-menu";
|
||||
private static final String ACTION = "action";
|
||||
private static final String ID = "id";
|
||||
private static final String DYEABLE = "dyeable";
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
private ItemSerializer() {
|
||||
}
|
||||
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException {
|
||||
private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path)
|
||||
throws SerializationException {
|
||||
if (!source.hasChild(path)) {
|
||||
throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node");
|
||||
throw new SerializationException(
|
||||
"Required field " + Arrays.toString(path) + " was not present in node");
|
||||
}
|
||||
|
||||
return source.node(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiItem deserialize(final Type type, final ConfigurationNode source) throws SerializationException {
|
||||
public GuiItem deserialize(final Type type, final ConfigurationNode source)
|
||||
throws SerializationException {
|
||||
final ConfigurationNode materialNode = this.nonVirtualNode(source, MATERIAL);
|
||||
final ConfigurationNode amountNode = source.node(AMOUNT);
|
||||
final ConfigurationNode nameNode = source.node(NAME);
|
||||
@@ -91,31 +98,41 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
final ConfigurationNode blueNode = colorNode.node(BLUE);
|
||||
final ConfigurationNode permissionNode = source.node(PERMISSION);
|
||||
final ConfigurationNode typeNode = source.node(TYPE);
|
||||
final ConfigurationNode openMenuNode = source.node(OPEN_MENU);
|
||||
final ConfigurationNode actionNode = source.node(ACTION);
|
||||
final ConfigurationNode idNode = source.node(ID);
|
||||
final ConfigurationNode dyeableNode = source.node(DYEABLE);
|
||||
|
||||
|
||||
final Material material = Utils.stringToEnum(Utils.replaceIfNull(materialNode.getString(), ""),
|
||||
Material.class, Material.AIR);
|
||||
final String materialString = Utils.replaceIfNull(materialNode.getString(), "");
|
||||
final int amount = amountNode.getInt();
|
||||
final Component name = StringUtils.parse(nameNode.getString());
|
||||
// Adventure.MINI_MESSAGE.parse(
|
||||
// Utils.replaceIfNull(nameNode.getString(), "")
|
||||
// );
|
||||
|
||||
ItemStack itemStack;
|
||||
|
||||
try {
|
||||
itemStack = new ItemStack(Material.valueOf(materialString), amount);
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
itemStack = HookManager.getInstance().getItemHooks().getItemStack(materialString);
|
||||
if (itemStack == null) {
|
||||
itemStack = new ItemStack(Material.AIR);
|
||||
}
|
||||
}
|
||||
|
||||
final String name = StringUtils.parseStringToString(nameNode.getString());
|
||||
|
||||
final boolean unbreakable = unbreakableNode.getBoolean();
|
||||
final boolean glowing = glowingNode.getBoolean();
|
||||
|
||||
final List<String> lore = Utils.replaceIfNull(loreNode.getList(String.class), new ArrayList<String>()).
|
||||
final List<String> lore = Utils.replaceIfNull(loreNode.getList(String.class),
|
||||
new ArrayList<String>()).
|
||||
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
|
||||
|
||||
final List<String> lockedLore = Utils.replaceIfNull(lockedLoreNode.getList(String.class), new ArrayList<String>()).
|
||||
final List<String> lockedLore = Utils.replaceIfNull(lockedLoreNode.getList(String.class),
|
||||
new ArrayList<String>()).
|
||||
stream().map(StringUtils::parseStringToString).collect(Collectors.toList());
|
||||
|
||||
final int modelData = modelDataNode.getInt();
|
||||
|
||||
final Set<ItemFlag> itemFlags = Utils.replaceIfNull(itemFlagsNode.getList(String.class), new ArrayList<String>()).
|
||||
final Set<ItemFlag> itemFlags = Utils.replaceIfNull(itemFlagsNode.getList(String.class),
|
||||
new ArrayList<String>()).
|
||||
stream().map(flag -> {
|
||||
try {
|
||||
return ItemFlag.valueOf(flag.toUpperCase());
|
||||
@@ -133,7 +150,7 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
if (colorNode.virtual()) {
|
||||
color = null;
|
||||
} else {
|
||||
color = Color.fromBGR(redNode.getInt(), greenNode.getInt(), blueNode.getInt());
|
||||
color = Color.fromRGB(redNode.getInt(), greenNode.getInt(), blueNode.getInt());
|
||||
}
|
||||
|
||||
final Map<Enchantment, Integer> enchantments =
|
||||
@@ -146,9 +163,10 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
return null;
|
||||
}
|
||||
|
||||
final NamespacedKey namespacedKey = NamespacedKey.minecraft(enchantmentString.
|
||||
split(":")[0].
|
||||
toLowerCase());
|
||||
final NamespacedKey namespacedKey = NamespacedKey.minecraft(
|
||||
enchantmentString.
|
||||
split(":")[0].
|
||||
toLowerCase());
|
||||
return Registry.ENCHANTMENT.get(namespacedKey);
|
||||
|
||||
}, enchantmentString -> {
|
||||
@@ -162,12 +180,10 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
final ItemBuilder itemBuilder;
|
||||
|
||||
if (material == Material.PLAYER_HEAD) {
|
||||
itemBuilder = SkullBuilder.
|
||||
create();
|
||||
if (itemStack.getType() == Material.PLAYER_HEAD) {
|
||||
itemBuilder = SkullBuilder.create();
|
||||
|
||||
if (texture != null) {
|
||||
((SkullBuilder) itemBuilder).texture(texture);
|
||||
@@ -175,28 +191,30 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
final OfflinePlayer player = Bukkit.getOfflinePlayer(owner);
|
||||
((SkullBuilder) itemBuilder).owner(player);
|
||||
}
|
||||
} else if (ColorBuilder.canBeColored(material)) {
|
||||
itemBuilder = ColorBuilder.from(material);
|
||||
} else if (ColorBuilder.canBeColored(itemStack)) {
|
||||
itemBuilder = ColorBuilder.from(itemStack);
|
||||
if (color != null) {
|
||||
((ColorBuilder) itemBuilder).color(color);
|
||||
}
|
||||
} else {
|
||||
itemBuilder = ItemBuilder.from(material);
|
||||
itemBuilder = ItemBuilder.from(itemStack);
|
||||
}
|
||||
|
||||
final ItemStack itemStack = itemBuilder.
|
||||
if (itemStack.getItemMeta() != null && !itemStack.getItemMeta().hasCustomModelData()) {
|
||||
itemBuilder.modelData(modelData);
|
||||
}
|
||||
|
||||
itemStack = itemBuilder.
|
||||
amount(amount).
|
||||
name(name).
|
||||
unbreakable(unbreakable).
|
||||
glow(glowing).
|
||||
lore(lore).
|
||||
modelData(modelData).
|
||||
enchants(enchantments, true).
|
||||
itemFlags(itemFlags).
|
||||
build();
|
||||
|
||||
final String openMenu = openMenuNode.getString(
|
||||
Utils.replaceIfNull(OPEN_MENU, ""));
|
||||
final GuiAction<InventoryClickEvent> action = ActionSerializer.INSTANCE.deserialize(GuiAction.class, actionNode);
|
||||
|
||||
Keys.setKey(itemStack);
|
||||
|
||||
@@ -211,23 +229,19 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
|
||||
return new ArmorItem(
|
||||
itemStack,
|
||||
event -> {
|
||||
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
|
||||
},
|
||||
action,
|
||||
Utils.replaceIfNull(idNode.getString(), ""),
|
||||
lockedLore,
|
||||
permission,
|
||||
cosmeticType,
|
||||
dyeable);
|
||||
dyeable,
|
||||
-1
|
||||
);
|
||||
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
return dev.triumphteam.gui.builder.item.ItemBuilder.from(
|
||||
itemStack).
|
||||
asGuiItem(event -> {
|
||||
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
plugin.getCosmeticsMenu().openMenu(openMenu, event.getWhoClicked());
|
||||
});
|
||||
final GuiItem guiItem = dev.triumphteam.gui.builder.item.ItemBuilder.from(itemStack).asGuiItem();
|
||||
guiItem.setAction(action);
|
||||
return guiItem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,4 +249,5 @@ public class ItemSerializer implements TypeSerializer<GuiItem> {
|
||||
public void serialize(final Type type, @Nullable final GuiItem obj, final ConfigurationNode node) throws SerializationException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
|
||||
public class Settings {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final CosmeticSettings cosmeticSettings;
|
||||
private final WardrobeSettings wardrobeSettings;
|
||||
|
||||
public Settings(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.cosmeticSettings = new CosmeticSettings();
|
||||
this.wardrobeSettings = new WardrobeSettings(this.plugin);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
this.plugin.saveDefaultConfig();
|
||||
this.plugin.reloadConfig();
|
||||
this.cosmeticSettings.load(this.plugin.getConfig());
|
||||
this.wardrobeSettings.load();
|
||||
}
|
||||
|
||||
public CosmeticSettings getCosmeticSettings() {
|
||||
return cosmeticSettings;
|
||||
}
|
||||
|
||||
public WardrobeSettings getWardrobeSettings() {
|
||||
return wardrobeSettings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SoundData {
|
||||
|
||||
private final String name;
|
||||
private final EnumWrappers.SoundCategory soundCategory;
|
||||
private final float volume;
|
||||
private final float pitch;
|
||||
|
||||
public SoundData(final String name, final EnumWrappers.SoundCategory soundCategory, final float volume, final float pitch) {
|
||||
this.name = name;
|
||||
this.soundCategory = soundCategory;
|
||||
this.volume = volume;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public float getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public EnumWrappers.SoundCategory getSoundCategory() {
|
||||
return soundCategory;
|
||||
}
|
||||
|
||||
public void play(final Player player) {
|
||||
final PacketContainer soundPacket = PacketManager.getSoundPacket(
|
||||
player,
|
||||
player.getLocation(),
|
||||
this.getKey(this.name),
|
||||
this.volume,
|
||||
this.pitch,
|
||||
this.soundCategory
|
||||
);
|
||||
|
||||
PacketManager.sendPacket(player, soundPacket);
|
||||
}
|
||||
|
||||
private MinecraftKey getKey(final String string) {
|
||||
if (!string.contains(":")) {
|
||||
return new MinecraftKey(string);
|
||||
}
|
||||
|
||||
final String[] parts = string.split(":");
|
||||
|
||||
return new MinecraftKey(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package io.github.fisher2911.hmccosmetics.config;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class WardrobeSettings {
|
||||
|
||||
private static final String WARDROBE_PATH = "wardrobe";
|
||||
private static final String DISABLE_ON_DAMAGE_PATH = WARDROBE_PATH + ".disable-on-damage";
|
||||
private static final String DISPLAY_RADIUS_PATH = WARDROBE_PATH + ".display-radius";
|
||||
private static final String PORTABLE_PATH = WARDROBE_PATH + ".portable";
|
||||
private static final String ALWAYS_DISPLAY_PATH = WARDROBE_PATH + ".always-display";
|
||||
private static final String STATIC_RADIUS_PATH = WARDROBE_PATH + ".static-radius";
|
||||
private static final String STATIC_LOCATION_PATH = WARDROBE_PATH + ".wardrobe-location";
|
||||
private static final String WORLD_PATH = "world";
|
||||
private static final String X_PATH = "x";
|
||||
private static final String Y_PATH = "y";
|
||||
private static final String Z_PATH = "z";
|
||||
private static final String YAW_PATH = "yaw";
|
||||
private static final String PITCH_PATH = "pitch";
|
||||
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
|
||||
private boolean disableOnDamage;
|
||||
private int displayRadius;
|
||||
private boolean portable;
|
||||
private boolean alwaysDisplay;
|
||||
private int staticRadius;
|
||||
private Location location;
|
||||
|
||||
public WardrobeSettings(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
final FileConfiguration config = this.plugin.getConfig();
|
||||
this.disableOnDamage = config.getBoolean(DISABLE_ON_DAMAGE_PATH);
|
||||
this.displayRadius = config.getInt(DISPLAY_RADIUS_PATH);
|
||||
this.portable = config.getBoolean(PORTABLE_PATH);
|
||||
this.staticRadius = config.getInt(STATIC_RADIUS_PATH);
|
||||
this.alwaysDisplay = config.getBoolean(ALWAYS_DISPLAY_PATH);
|
||||
final ConfigurationSection locationSection = config.getConfigurationSection(STATIC_LOCATION_PATH);
|
||||
if (locationSection == null) return;
|
||||
this.location = this.loadLocation(locationSection);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Location loadLocation(final ConfigurationSection section) {
|
||||
final String worldName = section.getString(WORLD_PATH);
|
||||
final double x = section.getDouble(X_PATH);
|
||||
final double y = section.getDouble(Y_PATH);
|
||||
final double z = section.getDouble(Z_PATH);
|
||||
final float yaw = (float) section.getDouble(YAW_PATH);
|
||||
final float pitch = (float) section.getDouble(PITCH_PATH);
|
||||
|
||||
if (worldName == null || worldName.isBlank()) return null;
|
||||
final World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) return null;
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
|
||||
public boolean getDisableOnDamage() {
|
||||
return disableOnDamage;
|
||||
}
|
||||
|
||||
public int getDisplayRadius() {
|
||||
return displayRadius;
|
||||
}
|
||||
|
||||
public boolean isPortable() {
|
||||
return portable;
|
||||
}
|
||||
|
||||
public boolean isAlwaysDisplay() {
|
||||
return alwaysDisplay;
|
||||
}
|
||||
|
||||
public int getStaticRadius() {
|
||||
return staticRadius;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location.clone();
|
||||
}
|
||||
|
||||
public boolean inDistanceOfWardrobe(final Location wardrobeLocation, final Location playerLocation) {
|
||||
if (this.displayRadius == -1) return true;
|
||||
return playerLocation.distanceSquared(wardrobeLocation) <= this.displayRadius * this.displayRadius;
|
||||
}
|
||||
|
||||
public boolean inDistanceOfStatic(final Location location) {
|
||||
if (this.location == null) return false;
|
||||
if (this.staticRadius == -1) return false;
|
||||
return this.location.distanceSquared(location) <= this.staticRadius * this.staticRadius;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.github.fisher2911.hmccosmetics.cosmetic;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CosmeticManager {
|
||||
|
||||
private final Map<String, ArmorItem> armorItemMap;
|
||||
|
||||
public CosmeticManager(final Map<String, ArmorItem> armorItemMap) {
|
||||
this.armorItemMap = armorItemMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ArmorItem getArmorItem(final String id) {
|
||||
return this.armorItemMap.get(id);
|
||||
}
|
||||
|
||||
public void addArmorItem(final ArmorItem armorItem) {
|
||||
this.armorItemMap.put(armorItem.getId(), armorItem);
|
||||
}
|
||||
|
||||
public Collection<ArmorItem> getAll() {
|
||||
return this.armorItemMap.values();
|
||||
}
|
||||
|
||||
public Map<String, ArmorItem> getArmorItemMap() {
|
||||
return armorItemMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package io.github.fisher2911.hmccosmetics.database;
|
||||
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.support.ConnectionSource;
|
||||
import com.j256.ormlite.table.TableUtils;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
|
||||
import io.github.fisher2911.hmccosmetics.database.dao.ArmorItemDAO;
|
||||
import io.github.fisher2911.hmccosmetics.database.dao.UserDAO;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class Database {
|
||||
|
||||
protected final HMCCosmetics plugin;
|
||||
final Dao<UserDAO, UUID> userDao;
|
||||
final Dao<ArmorItemDAO, UUID> armorItemDao;
|
||||
private final ConnectionSource dataSource;
|
||||
private final DatabaseType databaseType;
|
||||
AtomicInteger FAKE_ENTITY_ID = new AtomicInteger(Integer.MAX_VALUE);
|
||||
String TABLE_NAME = "user";
|
||||
String PLAYER_UUID_COLUMN = "uuid";
|
||||
String BACKPACK_COLUMN = "backpack";
|
||||
String HAT_COLUMN = "hat";
|
||||
String DYE_COLOR_COLUMN = "dye";
|
||||
String CREATE_TABLE_STATEMENT =
|
||||
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
|
||||
PLAYER_UUID_COLUMN + " CHAR(36), " +
|
||||
BACKPACK_COLUMN + " CHAR(50), " +
|
||||
HAT_COLUMN + " CHAR(50), " +
|
||||
DYE_COLOR_COLUMN + " INT, " +
|
||||
"UNIQUE (" +
|
||||
PLAYER_UUID_COLUMN +
|
||||
"))";
|
||||
|
||||
public Database(
|
||||
final HMCCosmetics plugin,
|
||||
final ConnectionSource dataSource,
|
||||
final DatabaseType databaseType) throws SQLException {
|
||||
this.plugin = plugin;
|
||||
this.dataSource = dataSource;
|
||||
this.userDao = DaoManager.createDao(this.dataSource, UserDAO.class);
|
||||
this.armorItemDao = DaoManager.createDao(this.dataSource, ArmorItemDAO.class);
|
||||
this.databaseType = databaseType;
|
||||
|
||||
}
|
||||
|
||||
public void load() {
|
||||
Threads.getInstance().execute(() -> new DatabaseConverter(this.plugin, this).convert());
|
||||
}
|
||||
|
||||
protected void createTables() {
|
||||
try {
|
||||
TableUtils.createTableIfNotExists(this.dataSource, ArmorItemDAO.class);
|
||||
TableUtils.createTableIfNotExists(this.dataSource, UserDAO.class);
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUser(final UUID uuid, final Consumer<User> onComplete) {
|
||||
final int armorStandId = FAKE_ENTITY_ID.getAndDecrement();
|
||||
final Wardrobe wardrobe = this.createNewWardrobe(uuid);
|
||||
Threads.getInstance().execute(
|
||||
() -> {
|
||||
try {
|
||||
UserDAO user = this.userDao.queryForId(uuid);
|
||||
|
||||
if (user == null) {
|
||||
user = this.userDao.createIfNotExists(new UserDAO(uuid));
|
||||
}
|
||||
|
||||
final List<ArmorItemDAO> armorItems = this.armorItemDao.queryForEq("uuid",
|
||||
uuid.toString());
|
||||
|
||||
final User actualUser = user.toUser(
|
||||
this.plugin.getCosmeticManager(),
|
||||
armorItems,
|
||||
wardrobe,
|
||||
armorStandId);
|
||||
Bukkit.getScheduler().runTask(this.plugin,
|
||||
() -> {
|
||||
this.plugin.getUserManager().add(
|
||||
actualUser
|
||||
);
|
||||
onComplete.accept(actualUser);
|
||||
}
|
||||
);
|
||||
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
final User user = new User(uuid, PlayerArmor.empty(), wardrobe, armorStandId);
|
||||
this.plugin.getUserManager().add(user);
|
||||
onComplete.accept(user);
|
||||
}
|
||||
|
||||
public void saveUser(final User user) {
|
||||
try {
|
||||
final UserDAO userDAO = new UserDAO(user.getUuid());
|
||||
this.userDao.createOrUpdate(userDAO);
|
||||
|
||||
final String uuid = user.getUuid().toString();
|
||||
for (final ArmorItem armorItem : user.getPlayerArmor().getArmorItems()) {
|
||||
final ArmorItemDAO dao = ArmorItemDAO.fromArmorItem(armorItem);
|
||||
dao.setUuid(uuid);
|
||||
this.armorItemDao.createOrUpdate(dao);
|
||||
}
|
||||
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
for (final User user : this.plugin.getUserManager().getAll()) {
|
||||
this.saveUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
this.dataSource.close();
|
||||
} catch (final Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected ConnectionSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public DatabaseType getDatabaseType() {
|
||||
return databaseType;
|
||||
}
|
||||
|
||||
public Dao<UserDAO, UUID> getUserDao() {
|
||||
return userDao;
|
||||
}
|
||||
|
||||
public Dao<ArmorItemDAO, UUID> getArmorItemDao() {
|
||||
return armorItemDao;
|
||||
}
|
||||
|
||||
public Wardrobe createNewWardrobe(final UUID ownerUUID) {
|
||||
return new Wardrobe(
|
||||
this.plugin,
|
||||
UUID.randomUUID(),
|
||||
ownerUUID,
|
||||
PlayerArmor.empty(),
|
||||
FAKE_ENTITY_ID.getAndDecrement(),
|
||||
FAKE_ENTITY_ID.getAndDecrement(),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package io.github.fisher2911.hmccosmetics.database;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import javax.swing.text.DateFormatter;
|
||||
|
||||
public class DatabaseConverter {
|
||||
|
||||
private static final int CURRENT_VERSION = 2;
|
||||
private static final String FILE_NAME = "info.yml";
|
||||
private final HMCCosmetics plugin;
|
||||
private final Database database;
|
||||
|
||||
public DatabaseConverter(final HMCCosmetics plugin, final Database database) {
|
||||
this.database = database;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void convert() {
|
||||
final File folder = new File(this.plugin.getDataFolder(), "database");
|
||||
|
||||
final File file = Path.of(
|
||||
folder.getPath(),
|
||||
FILE_NAME
|
||||
).toFile();
|
||||
|
||||
if (!file.exists()) {
|
||||
this.plugin.saveResource("database" + File.separator + FILE_NAME, true);
|
||||
}
|
||||
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
final int version = config.getInt("version") == 0 ? 1 : config.getInt("version");
|
||||
|
||||
final Set<User> users = new HashSet<>();
|
||||
|
||||
this.convert(version, users::add);
|
||||
|
||||
try {
|
||||
config.set("version", CURRENT_VERSION);
|
||||
config.save(file);
|
||||
} catch (final IOException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
this.database.createTables();
|
||||
|
||||
for (final User user : users) {
|
||||
database.saveUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void convert(final int version, final Consumer<User> consumer) {
|
||||
switch (version) {
|
||||
case 1 -> this.convertVersionOne(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertVersionOne(final Consumer<User> consumer) {
|
||||
final String query = "SELECT * from user";
|
||||
|
||||
try (final PreparedStatement statement = this.database.getDataSource()
|
||||
.getReadOnlyConnection("user").
|
||||
getUnderlyingConnection().prepareStatement(query)) {
|
||||
final ResultSet results = statement.executeQuery();
|
||||
try {
|
||||
|
||||
final Map<String, ArmorItem> armorItems = new ConcurrentHashMap<>(
|
||||
this.plugin.getCosmeticManager().getArmorItemMap());
|
||||
|
||||
while (results.next()) {
|
||||
final PlayerArmor playerArmor = PlayerArmor.empty();
|
||||
final UUID uuid = UUID.fromString(results.getString(1));
|
||||
final User user = new User(
|
||||
uuid,
|
||||
playerArmor,
|
||||
this.database.createNewWardrobe(uuid),
|
||||
this.database.FAKE_ENTITY_ID.getAndDecrement()
|
||||
);
|
||||
final String backpackId = results.getString(2);
|
||||
final String hatId = results.getString(3);
|
||||
final int hatDye = results.getInt(4);
|
||||
|
||||
final ArmorItem backpack = armorItems.get(backpackId);
|
||||
final ArmorItem hat = armorItems.get(hatId);
|
||||
if (backpack != null) {
|
||||
playerArmor.setItem(backpack);
|
||||
}
|
||||
if (hat != null) {
|
||||
hat.setDye(hatDye);
|
||||
playerArmor.setItem(hat);
|
||||
}
|
||||
|
||||
consumer.accept(user);
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
try (final PreparedStatement dropStatement = this.database.getDataSource()
|
||||
.getReadWriteConnection("user").
|
||||
getUnderlyingConnection().prepareStatement("DROP TABLE user")) {
|
||||
dropStatement.executeUpdate();
|
||||
} catch (final SQLException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package io.github.fisher2911.hmccosmetics.database;
|
||||
|
||||
import com.j256.ormlite.jdbc.DataSourceConnectionSource;
|
||||
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final Path FILE_PATH = HMCCosmetics.PLUGIN_FOLDER.resolve("database.yml");
|
||||
private static final String TYPE_PATH = "type";
|
||||
private static final String NAME_PATH = "name";
|
||||
private static final String USERNAME_PATH = "username";
|
||||
private static final String PASSWORD_PATH = "password";
|
||||
private static final String IP_PATH = "ip";
|
||||
private static final String PORT_PATH = "port";
|
||||
|
||||
public static Database create(final HMCCosmetics plugin) throws SQLException {
|
||||
if (!Files.exists(FILE_PATH)) {
|
||||
plugin.saveResource(FILE_PATH.getFileName().toString(), false);
|
||||
}
|
||||
|
||||
final FileConfiguration config = YamlConfiguration.loadConfiguration(FILE_PATH.toFile());
|
||||
|
||||
final String type = config.getString(TYPE_PATH);
|
||||
|
||||
final Logger logger = plugin.getLogger();
|
||||
|
||||
if (type == null) {
|
||||
logger.severe("Database type was null, disabling plugin.");
|
||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
final Database database = switch (type.toLowerCase()) {
|
||||
case "mysql" -> {
|
||||
final String name = config.getString(NAME_PATH);
|
||||
final String username = config.getString(USERNAME_PATH);
|
||||
final String password = config.getString(PASSWORD_PATH);
|
||||
final String ip = config.getString(IP_PATH);
|
||||
final String port = config.getString(PORT_PATH);
|
||||
|
||||
final HikariConfig hikari = new HikariConfig();
|
||||
|
||||
final String jdbcUrl = "jdbc:mysql://" + ip + ":" + port + "/" + name;
|
||||
|
||||
hikari.setJdbcUrl(jdbcUrl);
|
||||
hikari.setUsername(username);
|
||||
hikari.setPassword(password);
|
||||
hikari.setConnectionTimeout(1000000000);
|
||||
|
||||
final HikariDataSource source = new HikariDataSource(hikari);
|
||||
|
||||
yield new Database(
|
||||
plugin,
|
||||
new DataSourceConnectionSource(source, jdbcUrl),
|
||||
DatabaseType.MYSQL
|
||||
);
|
||||
}
|
||||
case "sqlite" -> {
|
||||
final File folder = new File(plugin.getDataFolder().getPath(), "database");
|
||||
folder.mkdirs();
|
||||
yield new Database(plugin, new JdbcPooledConnectionSource("jdbc:sqlite:" + new File(
|
||||
folder.getPath(),
|
||||
"users.db"
|
||||
).getPath()),
|
||||
DatabaseType.SQLITE
|
||||
);
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
|
||||
if (database == null) {
|
||||
logger.severe(
|
||||
"Error loading database, type " + type + " is invalid! Disabling plugin.");
|
||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.github.fisher2911.hmccosmetics.database;
|
||||
|
||||
public enum DatabaseType {
|
||||
|
||||
MYSQL,
|
||||
SQLITE
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package io.github.fisher2911.hmccosmetics.database.dao;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import java.util.Objects;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@DatabaseTable(tableName = "armor_items")
|
||||
public class ArmorItemDAO {
|
||||
|
||||
@DatabaseField(columnName = "uuid", useGetSet = true, uniqueCombo = true)
|
||||
private String uuid;
|
||||
|
||||
@DatabaseField
|
||||
private String id;
|
||||
|
||||
@DatabaseField(id = true, useGetSet = true, columnName = "artificial_id")
|
||||
private String artificialId;
|
||||
|
||||
@DatabaseField(uniqueCombo = true)
|
||||
private String type;
|
||||
|
||||
@DatabaseField(columnName = "color")
|
||||
private int rgbDye;
|
||||
|
||||
public ArmorItemDAO(final String id, final String type, final int rgbDye) {
|
||||
this.id = id;
|
||||
this.artificialId = this.getArtificialId();
|
||||
this.type = type;
|
||||
this.rgbDye = rgbDye;
|
||||
}
|
||||
|
||||
public ArmorItemDAO() {
|
||||
}
|
||||
|
||||
public static ArmorItemDAO fromArmorItem(final ArmorItem armorItem) {
|
||||
return new ArmorItemDAO(armorItem.getId(), armorItem.getType().toString(),
|
||||
armorItem.getDye());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ArmorItem toArmorItem(final CosmeticManager cosmeticManager) {
|
||||
final ArmorItem armorItem = cosmeticManager.getArmorItem(this.id);
|
||||
if (armorItem == null) {
|
||||
return null;
|
||||
}
|
||||
final ArmorItem copy = new ArmorItem(armorItem);
|
||||
copy.setDye(this.rgbDye);
|
||||
return copy;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(final String uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* ORMLite does not allow more than one primary key (WHYYYY???????????)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getArtificialId() {
|
||||
return this.uuid + "-" + this.type;
|
||||
}
|
||||
|
||||
public void setArtificialId(final String artificialId) {
|
||||
this.artificialId = artificialId;
|
||||
}
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getRgbDye() {
|
||||
return rgbDye;
|
||||
}
|
||||
|
||||
public void setRgbDye(final int rgbDye) {
|
||||
this.rgbDye = rgbDye;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ArmorItemDAO that = (ArmorItemDAO) o;
|
||||
return Objects.equals(getUuid(), that.getUuid()) && Objects.equals(getType(),
|
||||
that.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getUuid(), getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArmorItemDAO{" +
|
||||
"uuid='" + uuid + '\'' +
|
||||
", id='" + id + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", rgbDye=" + rgbDye +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.github.fisher2911.hmccosmetics.database.dao;
|
||||
|
||||
import com.j256.ormlite.field.DatabaseField;
|
||||
import com.j256.ormlite.table.DatabaseTable;
|
||||
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@DatabaseTable(tableName = "user")
|
||||
public class UserDAO {
|
||||
|
||||
@DatabaseField(id = true)
|
||||
private UUID uuid;
|
||||
|
||||
public UserDAO() {
|
||||
}
|
||||
|
||||
public UserDAO(final UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setUuid(final UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public User toUser(
|
||||
final CosmeticManager cosmeticManager,
|
||||
final List<ArmorItemDAO> armorItems,
|
||||
final Wardrobe wardrobe,
|
||||
final int armorStandId) {
|
||||
final PlayerArmor playerArmor = PlayerArmor.empty();
|
||||
|
||||
for (final ArmorItemDAO armorItemDao : armorItems) {
|
||||
final ArmorItem armorItem = armorItemDao.toArmorItem(cosmeticManager);
|
||||
if (armorItem == null) {
|
||||
continue;
|
||||
}
|
||||
playerArmor.setItem(armorItem);
|
||||
}
|
||||
|
||||
return new User(this.uuid, playerArmor, wardrobe, armorStandId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserDAO{" +
|
||||
"uuid=" + uuid +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final UserDAO userDAO = (UserDAO) o;
|
||||
return Objects.equals(uuid, userDAO.uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uuid);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,81 +2,27 @@ package io.github.fisher2911.hmccosmetics.gui;
|
||||
|
||||
import dev.triumphteam.gui.components.GuiAction;
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ColorBuilder;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ArmorItem extends GuiItem {
|
||||
|
||||
private final String id;
|
||||
private final List<String> lockedLore;
|
||||
private final GuiAction<InventoryClickEvent> action;
|
||||
private final String permission;
|
||||
private final Type type;
|
||||
private GuiAction<InventoryClickEvent> action;
|
||||
private boolean dyeable;
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final ItemStack itemStack,
|
||||
final GuiAction<InventoryClickEvent> action,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type) {
|
||||
super(itemStack, action);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = action;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final ItemStack itemStack,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type) {
|
||||
super(itemStack);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final Material material,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type) {
|
||||
super(material);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final Material material,
|
||||
@Nullable final GuiAction<InventoryClickEvent> action,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type) {
|
||||
super(material, action);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = action;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
}
|
||||
private int dye;
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final ItemStack itemStack,
|
||||
@@ -85,14 +31,15 @@ public class ArmorItem extends GuiItem {
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable) {
|
||||
final int dye) {
|
||||
super(itemStack, action);
|
||||
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = action;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@@ -101,14 +48,14 @@ public class ArmorItem extends GuiItem {
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable) {
|
||||
final int dye) {
|
||||
super(itemStack);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@@ -117,14 +64,14 @@ public class ArmorItem extends GuiItem {
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable) {
|
||||
final int dye) {
|
||||
super(material);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@@ -134,7 +81,80 @@ public class ArmorItem extends GuiItem {
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable) {
|
||||
final int dye) {
|
||||
super(material, action);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = action;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final ItemStack itemStack,
|
||||
final GuiAction<InventoryClickEvent> action,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable,
|
||||
final int dye) {
|
||||
super(itemStack, action);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = action;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final ItemStack itemStack,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable,
|
||||
final int dye) {
|
||||
super(itemStack);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final Material material,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable,
|
||||
final int dye) {
|
||||
super(material);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
this.action = null;
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(
|
||||
@NotNull final Material material,
|
||||
@Nullable final GuiAction<InventoryClickEvent> action,
|
||||
final String id,
|
||||
final List<String> lockedLore,
|
||||
final String permission,
|
||||
final Type type,
|
||||
final boolean dyeable,
|
||||
final int dye) {
|
||||
super(material, action);
|
||||
this.id = id;
|
||||
this.lockedLore = lockedLore;
|
||||
@@ -142,6 +162,30 @@ public class ArmorItem extends GuiItem {
|
||||
this.permission = permission;
|
||||
this.type = type;
|
||||
this.dyeable = dyeable;
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ArmorItem(final ArmorItem armorItem) {
|
||||
super(armorItem.getItemStack(), armorItem.getAction());
|
||||
this.id = armorItem.getId();
|
||||
this.lockedLore = new ArrayList<>();
|
||||
Collections.copy(armorItem.getLockedLore(), this.lockedLore);
|
||||
this.action = armorItem.getAction();
|
||||
this.permission = armorItem.getPermission();
|
||||
this.type = armorItem.getType();
|
||||
this.dyeable = armorItem.isDyeable();
|
||||
this.dye = armorItem.getDye();
|
||||
}
|
||||
|
||||
public static ArmorItem empty(final Type type) {
|
||||
return new ArmorItem(
|
||||
new ItemStack(Material.AIR),
|
||||
"",
|
||||
new ArrayList<>(),
|
||||
"",
|
||||
type,
|
||||
-1
|
||||
);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@@ -156,6 +200,12 @@ public class ArmorItem extends GuiItem {
|
||||
return this.action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAction(final GuiAction<InventoryClickEvent> action) {
|
||||
super.setAction(action);
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
@@ -168,21 +218,56 @@ public class ArmorItem extends GuiItem {
|
||||
return dyeable;
|
||||
}
|
||||
|
||||
public int getDye() {
|
||||
return dye;
|
||||
}
|
||||
|
||||
public void setDye(final int dye) {
|
||||
this.dye = dye;
|
||||
}
|
||||
|
||||
public ItemStack getColored() {
|
||||
return this.color(super.getItemStack());
|
||||
}
|
||||
|
||||
public ItemStack getItemStack(final boolean allowed) {
|
||||
final ItemStack itemStack;
|
||||
|
||||
if (allowed) {
|
||||
return this.getItemStack();
|
||||
itemStack = super.getItemStack();
|
||||
} else {
|
||||
itemStack = ItemBuilder.from(this.getItemStack()).
|
||||
lore(this.lockedLore).
|
||||
build();
|
||||
}
|
||||
|
||||
return ItemBuilder.from(this.getItemStack()).
|
||||
lore(lockedLore).
|
||||
return this.color(itemStack);
|
||||
}
|
||||
|
||||
private ItemStack color(final ItemStack itemStack) {
|
||||
if (this.dye == -1 || !ColorBuilder.canBeColored(itemStack)) {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
return ColorBuilder.from(itemStack).
|
||||
color(Color.fromRGB(this.dye)).
|
||||
build();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.getItemStack().getType() == Material.AIR;
|
||||
}
|
||||
|
||||
public ArmorItem copy() {
|
||||
return new ArmorItem(this);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
HAT,
|
||||
|
||||
BACKPACK
|
||||
BACKPACK,
|
||||
OFF_HAND
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@ public class ColorItem extends GuiItem {
|
||||
|
||||
private final Color color;
|
||||
|
||||
public ColorItem(final @NotNull ItemStack itemStack, final GuiAction<InventoryClickEvent> action, final Color color) {
|
||||
public ColorItem(final @NotNull ItemStack itemStack,
|
||||
final GuiAction<InventoryClickEvent> action,
|
||||
final Color color) {
|
||||
super(itemStack, action);
|
||||
this.color = color;
|
||||
}
|
||||
@@ -28,7 +30,8 @@ public class ColorItem extends GuiItem {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public ColorItem(final @NotNull Material material, final @Nullable GuiAction<InventoryClickEvent> action, final Color color) {
|
||||
public ColorItem(final @NotNull Material material,
|
||||
final @Nullable GuiAction<InventoryClickEvent> action, final Color color) {
|
||||
super(material, action);
|
||||
this.color = color;
|
||||
}
|
||||
@@ -36,4 +39,5 @@ public class ColorItem extends GuiItem {
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package io.github.fisher2911.hmccosmetics.gui;
|
||||
|
||||
import dev.triumphteam.gui.components.GuiAction;
|
||||
import dev.triumphteam.gui.guis.Gui;
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
|
||||
import io.github.fisher2911.hmccosmetics.message.Messages;
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CosmeticGui {
|
||||
|
||||
private static final float COOL_DOWN = 0.5f;
|
||||
protected final HMCCosmetics plugin;
|
||||
protected final MessageHandler messageHandler;
|
||||
protected final String title;
|
||||
protected final int rows;
|
||||
protected final Map<Integer, ItemStack> itemStackMap;
|
||||
protected final Map<Integer, GuiItem> guiItemMap;
|
||||
protected Gui gui;
|
||||
private long lastClicked;
|
||||
|
||||
public CosmeticGui(
|
||||
final HMCCosmetics plugin,
|
||||
final String title,
|
||||
final int rows,
|
||||
final Map<Integer, GuiItem> guiItemMap) {
|
||||
this.plugin = plugin;
|
||||
this.messageHandler = this.plugin.getMessageHandler();
|
||||
this.title = title;
|
||||
this.rows = rows;
|
||||
this.guiItemMap = guiItemMap;
|
||||
this.itemStackMap = new HashMap<>();
|
||||
this.guiItemMap.forEach((key, value) -> itemStackMap.put(key, value.getItemStack()));
|
||||
}
|
||||
|
||||
private void setItems(final User user) {
|
||||
final Player player = user.getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final var entry : guiItemMap.entrySet()) {
|
||||
final int slot = entry.getKey();
|
||||
|
||||
final GuiItem guiItem = this.getGuiItem(user, player, slot);
|
||||
if (guiItem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.gui.setItem(slot, guiItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUserArmor(
|
||||
final HumanEntity human,
|
||||
final User user,
|
||||
final ArmorItem armorItem,
|
||||
final InventoryClickEvent event,
|
||||
final GuiAction<InventoryClickEvent> actionIfSet) {
|
||||
|
||||
final long current = System.currentTimeMillis();
|
||||
if ((current - this.lastClicked) / 1000. < COOL_DOWN) {
|
||||
return;
|
||||
}
|
||||
this.lastClicked = current;
|
||||
|
||||
if (!(human instanceof final Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ArmorItem.Type type = armorItem.getType();
|
||||
|
||||
final ArmorItem setTo = this.plugin.getUserManager().setOrUnset(
|
||||
user,
|
||||
armorItem,
|
||||
Messages.getRemovedMessage(type),
|
||||
Messages.getSetMessage(type)
|
||||
);
|
||||
|
||||
if (!setTo.isEmpty()) {
|
||||
actionIfSet.execute(event);
|
||||
}
|
||||
|
||||
final int slot = event.getSlot();
|
||||
|
||||
final GuiItem guiItem = this.getGuiItem(user, player, slot);
|
||||
|
||||
if (guiItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.gui.updateItem(slot, guiItem);
|
||||
}
|
||||
|
||||
public void open(final User user, final Player player) {
|
||||
this.gui = Gui.gui().
|
||||
title(Adventure.MINI_MESSAGE.deserialize(
|
||||
Placeholder.applyPapiPlaceholders(player, this.title))).
|
||||
rows(this.rows).
|
||||
create();
|
||||
|
||||
this.gui.setDefaultClickAction(event -> event.setCancelled(true));
|
||||
|
||||
this.setItems(user);
|
||||
|
||||
this.gui.open(player);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GuiItem getGuiItem(final User user, final Player player, final int slot) {
|
||||
final GuiItem guiItem = this.guiItemMap.get(slot);
|
||||
|
||||
if (guiItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ItemStack itemStack = this.itemStackMap.get(slot);
|
||||
|
||||
if (itemStack == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (guiItem instanceof final ArmorItem armorItem) {
|
||||
final String permission =
|
||||
armorItem.getPermission() == null ? "" : armorItem.getPermission();
|
||||
|
||||
final boolean hasPermission = permission.isBlank() || user.hasPermissionToUse(armorItem);
|
||||
|
||||
return new GuiItem(
|
||||
this.applyPlaceholders(user, player, armorItem, hasPermission),
|
||||
event -> {
|
||||
if (!hasPermission) {
|
||||
this.messageHandler.sendMessage(
|
||||
player,
|
||||
Messages.NO_COSMETIC_PERMISSION
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final ArmorItem cosmeticItem = this.plugin.getCosmeticManager()
|
||||
.getArmorItem(armorItem.getId());
|
||||
|
||||
if (cosmeticItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setUserArmor(player, user, cosmeticItem, event, armorItem.getAction());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
guiItem.setItemStack(
|
||||
ItemBuilder.from(itemStack.clone()).papiPlaceholders(player).build()
|
||||
);
|
||||
|
||||
return guiItem;
|
||||
}
|
||||
|
||||
protected ItemStack applyPlaceholders(final User user, final Player player,
|
||||
final ArmorItem armorItem, final boolean hasPermission) {
|
||||
final Map<String, String> placeholders = new HashMap<>();
|
||||
|
||||
final PlayerArmor playerArmor = user.getPlayerArmor();
|
||||
|
||||
final ArmorItem.Type type = armorItem.getType();
|
||||
|
||||
final String id = playerArmor.getItem(type).getId();
|
||||
|
||||
placeholders.put(
|
||||
Placeholder.ENABLED,
|
||||
String.valueOf(id.equals(armorItem.getId())).
|
||||
toLowerCase(Locale.ROOT));
|
||||
|
||||
placeholders.put(
|
||||
Placeholder.ALLOWED,
|
||||
String.valueOf(hasPermission).
|
||||
toLowerCase(Locale.ROOT));
|
||||
|
||||
final ItemStack itemStack;
|
||||
|
||||
if (!hasPermission) {
|
||||
itemStack = armorItem.getItemStack(false);
|
||||
} else {
|
||||
itemStack = armorItem.getColored();
|
||||
}
|
||||
|
||||
return ItemBuilder.from(
|
||||
itemStack
|
||||
).namePlaceholders(placeholders).
|
||||
lorePlaceholders(placeholders).
|
||||
papiPlaceholders(player).
|
||||
build();
|
||||
}
|
||||
|
||||
public CosmeticGui copy() {
|
||||
return new CosmeticGui(
|
||||
this.plugin,
|
||||
this.title,
|
||||
this.rows,
|
||||
new HashMap<>(this.guiItemMap)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package io.github.fisher2911.hmccosmetics.gui;
|
||||
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.config.DyeGuiSerializer;
|
||||
import io.github.fisher2911.hmccosmetics.config.GuiSerializer;
|
||||
import io.github.fisher2911.hmccosmetics.config.ItemSerializer;
|
||||
import io.github.fisher2911.hmccosmetics.cosmetic.CosmeticManager;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class CosmeticsMenu {
|
||||
|
||||
public static final String DEFAULT_MAIN_MENU = "main";
|
||||
public static final String DEFAULT_DYE_MENU = "dye-menu";
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final CosmeticManager cosmeticManager;
|
||||
|
||||
private final Map<String, CosmeticGui> guiMap = new HashMap<>();
|
||||
|
||||
private final Set<String> registeredPermissions = new HashSet<>();
|
||||
|
||||
public CosmeticsMenu(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.cosmeticManager = this.plugin.getCosmeticManager();
|
||||
}
|
||||
|
||||
public void openMenu(final String id, final HumanEntity humanEntity) {
|
||||
if (!(humanEntity instanceof final Player player)) return;
|
||||
final CosmeticGui cosmeticGui = this.getGui(id);
|
||||
|
||||
final Optional<User> optionalUser = this.plugin.getUserManager().get(humanEntity.getUniqueId());
|
||||
|
||||
if (optionalUser.isEmpty()) return;
|
||||
|
||||
User user = optionalUser.get();
|
||||
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
if (wardrobe.isActive()) user = wardrobe;
|
||||
|
||||
if (cosmeticGui instanceof final DyeSelectorGui dyeSelectorGui) {
|
||||
dyeSelectorGui.getGui(user, user.getLastSetItem().getType()).open(humanEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cosmeticGui != null) cosmeticGui.open(user, player);
|
||||
}
|
||||
|
||||
public void openDefault(final HumanEntity humanEntity) {
|
||||
this.openMenu(DEFAULT_MAIN_MENU, humanEntity);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
for (final ArmorItem armorItem : this.cosmeticManager.getAll()) {
|
||||
Bukkit.getPluginManager().removePermission(new Permission(armorItem.getPermission()));
|
||||
}
|
||||
this.load();
|
||||
}
|
||||
|
||||
public void openDyeSelectorGui(
|
||||
User user,
|
||||
final ArmorItem.Type type) {
|
||||
|
||||
final Player player = user.getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
if (wardrobe.isActive()) user = wardrobe;
|
||||
|
||||
final CosmeticGui gui = this.getGui(DEFAULT_DYE_MENU);
|
||||
|
||||
if (gui instanceof final DyeSelectorGui dyeSelectorGui) {
|
||||
dyeSelectorGui.getGui(user, type).open(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CosmeticGui getGui(final String id) {
|
||||
final CosmeticGui gui = this.guiMap.get(id);
|
||||
if (gui == null) return null;
|
||||
return gui.copy();
|
||||
}
|
||||
|
||||
private static final String GUI_TYPE = "gui-type";
|
||||
private static final String DYE_TYPE = "dye";
|
||||
|
||||
public void load() {
|
||||
this.guiMap.clear();
|
||||
final File file = Path.of(this.plugin.getDataFolder().getPath(),
|
||||
"menus").toFile();
|
||||
|
||||
if (!Path.of(this.plugin.getDataFolder().getPath(),
|
||||
"menus",
|
||||
DEFAULT_MAIN_MENU + ".yml").toFile().exists()) {
|
||||
this.plugin.saveResource(
|
||||
new File("menus", DEFAULT_MAIN_MENU + ".yml").getPath(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (!Path.of(this.plugin.getDataFolder().getPath(),
|
||||
"menus",
|
||||
DEFAULT_DYE_MENU + ".yml").toFile().exists()) {
|
||||
this.plugin.saveResource(
|
||||
new File("menus", DEFAULT_DYE_MENU + ".yml").getPath(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (!file.exists() ||
|
||||
!file.isDirectory()) {
|
||||
this.plugin.getLogger().severe("No directory found");
|
||||
return;
|
||||
}
|
||||
|
||||
final File[] files = file.listFiles();
|
||||
|
||||
if (files == null) {
|
||||
this.plugin.getLogger().severe("Files are null");
|
||||
return;
|
||||
}
|
||||
|
||||
for (final File guiFile : files) {
|
||||
final String id = guiFile.getName().replace(".yml", "");
|
||||
|
||||
final YamlConfigurationLoader loader = YamlConfigurationLoader.
|
||||
builder().
|
||||
path(Path.of(guiFile.getPath())).
|
||||
defaultOptions(opts ->
|
||||
opts.serializers(build -> {
|
||||
build.register(GuiItem.class, ItemSerializer.INSTANCE);
|
||||
build.register(CosmeticGui.class, GuiSerializer.INSTANCE);
|
||||
build.register(DyeSelectorGui.class, DyeGuiSerializer.INSTANCE);
|
||||
}))
|
||||
.build();
|
||||
|
||||
try {
|
||||
final ConfigurationNode source = loader.load();
|
||||
final ConfigurationNode typeNode = source.node(GUI_TYPE);
|
||||
|
||||
final String type;
|
||||
|
||||
if (typeNode != null) {
|
||||
type = typeNode.getString();
|
||||
} else {
|
||||
type = "";
|
||||
}
|
||||
|
||||
if (id.equals(DEFAULT_DYE_MENU) || DYE_TYPE.equals(type)) {
|
||||
this.guiMap.put(id, DyeGuiSerializer.INSTANCE.deserialize(DyeSelectorGui.class, source));
|
||||
this.plugin.getLogger().info("Loaded dye gui: " + id);
|
||||
continue;
|
||||
}
|
||||
|
||||
final CosmeticGui gui = source.get(CosmeticGui.class);
|
||||
|
||||
if (gui == null) continue;
|
||||
|
||||
for (final GuiItem guiItem : gui.guiItemMap.values()) {
|
||||
if (guiItem instanceof final ArmorItem item) {
|
||||
final ArmorItem copy = new ArmorItem(item);
|
||||
copy.setAction(null);
|
||||
this.cosmeticManager.addArmorItem(copy);
|
||||
final String perm = copy.getPermission();
|
||||
if (perm.isBlank() || this.registeredPermissions.contains(perm)) continue;
|
||||
Bukkit.getPluginManager().addPermission(new Permission(perm));
|
||||
}
|
||||
}
|
||||
|
||||
this.guiMap.put(id, source.get(CosmeticGui.class));
|
||||
this.plugin.getLogger().info("Loaded gui: " + id);
|
||||
} catch (final ConfigurateException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package io.github.fisher2911.hmccosmetics.gui;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import dev.triumphteam.gui.guis.Gui;
|
||||
import dev.triumphteam.gui.guis.GuiItem;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class DyeSelectorGui extends CosmeticGui {
|
||||
|
||||
private final BiMap<Integer, ArmorItem.Type> cosmeticsSlots;
|
||||
private int selectedCosmetic;
|
||||
|
||||
public DyeSelectorGui(
|
||||
final HMCCosmetics plugin,
|
||||
final String title,
|
||||
final int rows,
|
||||
final Map<Integer, GuiItem> guiItemMap,
|
||||
final BiMap<Integer, ArmorItem.Type> cosmeticsSlots,
|
||||
final int selectedCosmetic
|
||||
) {
|
||||
super(plugin, title, rows, guiItemMap);
|
||||
this.cosmeticsSlots = cosmeticsSlots;
|
||||
this.selectedCosmetic = selectedCosmetic;
|
||||
}
|
||||
|
||||
public Gui getGui(final User user) {
|
||||
return this.getGui(user, null);
|
||||
}
|
||||
|
||||
public Gui getGui(final User user, @Nullable final ArmorItem.Type type) {
|
||||
this.gui = Gui.gui().
|
||||
title(Component.text(
|
||||
Placeholder.applyPapiPlaceholders(user.getPlayer(), this.title))).
|
||||
rows(rows).
|
||||
create();
|
||||
|
||||
final Player player = user.getPlayer();
|
||||
|
||||
if (type != null) {
|
||||
final Integer selected = this.cosmeticsSlots.inverse().get(type);
|
||||
this.selectedCosmetic = selected == null ? this.selectedCosmetic : selected;
|
||||
}
|
||||
|
||||
for (final var entry : this.cosmeticsSlots.entrySet()) {
|
||||
gui.setItem(
|
||||
entry.getKey(),
|
||||
new GuiItem(
|
||||
this.applyPlaceholders(
|
||||
user,
|
||||
player,
|
||||
user.getPlayerArmor().getItem(entry.getValue()),
|
||||
true
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
for (final var entry : this.guiItemMap.entrySet()) {
|
||||
|
||||
final GuiItem guiItem = entry.getValue();
|
||||
|
||||
final ItemStack itemStack = this.itemStackMap.get(entry.getKey());
|
||||
|
||||
if (itemStack == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
guiItem.setItemStack(
|
||||
ItemBuilder.from(itemStack.clone()).papiPlaceholders(player).build()
|
||||
);
|
||||
|
||||
gui.setItem(entry.getKey(), guiItem);
|
||||
}
|
||||
|
||||
final PlayerArmor playerArmor = user.getPlayerArmor();
|
||||
|
||||
this.select(this.selectedCosmetic, user, player);
|
||||
|
||||
gui.setDefaultClickAction(event -> {
|
||||
event.setCancelled(true);
|
||||
|
||||
final ArmorItem armorItem = playerArmor.getItem(
|
||||
this.cosmeticsSlots.get(this.selectedCosmetic)
|
||||
);
|
||||
|
||||
if (armorItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack itemStack = playerArmor.getItem(type).getItemStack();
|
||||
|
||||
if (itemStack == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int slot = event.getSlot();
|
||||
|
||||
final ArmorItem.Type clickedType = this.cosmeticsSlots.get(slot);
|
||||
|
||||
if (clickedType != null) {
|
||||
this.select(slot, user, player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!armorItem.isDyeable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final GuiItem guiItem = this.guiItemMap.get(slot);
|
||||
|
||||
if (!(guiItem instanceof ColorItem colorItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
armorItem.setDye(colorItem.getColor().asRGB());
|
||||
|
||||
this.plugin.getUserManager().setItem(user, armorItem);
|
||||
this.updateSelected(user, player);
|
||||
});
|
||||
|
||||
return gui;
|
||||
}
|
||||
|
||||
private void select(final int slot, final User user, final Player player) {
|
||||
|
||||
final PlayerArmor playerArmor = user.getPlayerArmor();
|
||||
|
||||
final ItemStack previous = this.applyPlaceholders(
|
||||
user,
|
||||
player,
|
||||
playerArmor.getItem(this.cosmeticsSlots.get(this.selectedCosmetic)),
|
||||
true
|
||||
);
|
||||
|
||||
if (previous != null && previous.getType() != Material.AIR) {
|
||||
final ItemStack previousItem = dev.triumphteam.gui.builder.item.ItemBuilder.from(
|
||||
previous
|
||||
).glow(false).build();
|
||||
|
||||
this.gui.updateItem(this.selectedCosmetic, previousItem);
|
||||
}
|
||||
|
||||
this.selectedCosmetic = slot;
|
||||
|
||||
this.updateSelected(user, player);
|
||||
}
|
||||
|
||||
private void updateSelected(final User user, final Player player) {
|
||||
final ArmorItem.Type type = this.cosmeticsSlots.get(this.selectedCosmetic);
|
||||
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.gui.updateItem(this.selectedCosmetic,
|
||||
|
||||
ItemBuilder.from(
|
||||
this.applyPlaceholders(
|
||||
user, player, user.getPlayerArmor().getItem(type), true
|
||||
)
|
||||
).glow(true).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(final User user, final Player player) {
|
||||
this.getGui(user, user.getLastSetItem().getType()).open(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
public DyeSelectorGui copy() {
|
||||
return new DyeSelectorGui(
|
||||
this.plugin,
|
||||
super.title,
|
||||
super.rows,
|
||||
new HashMap<>(super.guiItemMap),
|
||||
HashBiMap.create(this.cosmeticsSlots),
|
||||
this.selectedCosmetic
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook;
|
||||
|
||||
public interface Hook {
|
||||
|
||||
String getId();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.ItemHook;
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.ItemHooks;
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.ItemsAdderHook;
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.OraxenHook;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.hook.item.PAPIExpansion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HookManager {
|
||||
|
||||
private static final HookManager INSTANCE;
|
||||
|
||||
static {
|
||||
INSTANCE = new HookManager(HMCCosmetics.getPlugin(HMCCosmetics.class));
|
||||
}
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final ItemHooks itemHooks;
|
||||
private final PAPIHook papiHook;
|
||||
private final Set<Class<? extends Hook>> registeredHooks;
|
||||
private final Set<Listener> listeners;
|
||||
|
||||
private HookManager(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.registeredHooks = new HashSet<>();
|
||||
this.listeners = new HashSet<>();
|
||||
final PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
if (pluginManager.getPlugin("PlaceholderApi") != null) {
|
||||
this.registeredHooks.add(PAPIHook.class);
|
||||
this.papiHook = new PAPIHook();
|
||||
} else {
|
||||
this.papiHook = null;
|
||||
}
|
||||
|
||||
final Map<String, ItemHook> itemHookMap = new HashMap<>();
|
||||
final OraxenHook oraxenHook = new OraxenHook();
|
||||
final ItemsAdderHook itemsAdderHook = new ItemsAdderHook();
|
||||
if (pluginManager.getPlugin("Oraxen") != null) {
|
||||
itemHookMap.put(oraxenHook.getIdentifier(), oraxenHook);
|
||||
}
|
||||
if (pluginManager.getPlugin("ItemsAdder") != null) {
|
||||
itemHookMap.put(itemsAdderHook.getIdentifier(), itemsAdderHook);
|
||||
this.listeners.add(itemsAdderHook);
|
||||
}
|
||||
|
||||
this.itemHooks = new ItemHooks(itemHookMap);
|
||||
itemHookMap.values().forEach(hook -> this.registerHook(hook.getClass()));
|
||||
}
|
||||
|
||||
public static HookManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
protected void registerHook(final Class<? extends Hook> hook) {
|
||||
this.registeredHooks.add(hook);
|
||||
}
|
||||
|
||||
public boolean isEnabled(final Class<? extends Hook> hook) {
|
||||
return this.registeredHooks.contains(hook);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (this.isEnabled(PAPIHook.class)) {
|
||||
new PAPIExpansion(this.plugin).register();
|
||||
}
|
||||
this.registerListeners(this.plugin);
|
||||
}
|
||||
|
||||
public void registerListeners(final HMCCosmetics plugin) {
|
||||
for (final Listener listener : this.listeners) {
|
||||
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PAPIHook getPapiHook() {
|
||||
return papiHook;
|
||||
}
|
||||
|
||||
public ItemHooks getItemHooks() {
|
||||
return itemHooks;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PAPIHook implements Hook {
|
||||
|
||||
private static final String ID = "PAPI";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public String parse(final Player player, final String string) {
|
||||
return PlaceholderAPI.setPlaceholders(player, string);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook.item;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.hook.Hook;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public interface ItemHook extends Hook {
|
||||
|
||||
String getIdentifier();
|
||||
|
||||
ItemStack getItem(final String id);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook.item;
|
||||
|
||||
import java.util.Map;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ItemHooks {
|
||||
|
||||
private final Map<String, ItemHook> itemHookMap;
|
||||
|
||||
public ItemHooks(final Map<String, ItemHook> itemHookMap) {
|
||||
this.itemHookMap = itemHookMap;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItemStack(final String item) {
|
||||
final String[] parts = item.split(":");
|
||||
|
||||
if (parts.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String identifier = parts[0];
|
||||
final StringBuilder itemId = new StringBuilder();
|
||||
|
||||
for (int i = 1; i < parts.length; i++) {
|
||||
itemId.append(parts[i]);
|
||||
if (i < parts.length - 1) {
|
||||
itemId.append(":");
|
||||
}
|
||||
}
|
||||
|
||||
final ItemHook hook = this.itemHookMap.get(identifier);
|
||||
|
||||
if (hook == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return hook.getItem(itemId.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook.item;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemsAdderHook implements ItemHook, Listener {
|
||||
|
||||
public static final String ID = "ITEM_ADDER";
|
||||
private static final String IDENTIFIER = "itemsadder";
|
||||
|
||||
@EventHandler
|
||||
public void onItemsAdderLoad(final ItemsAdderLoadDataEvent event) {
|
||||
final HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, plugin::load);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(final String id) {
|
||||
final CustomStack stack = CustomStack.getInstance(id);
|
||||
if (stack == null) {
|
||||
return null;
|
||||
}
|
||||
return stack.getItemStack().clone();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook.item;
|
||||
|
||||
import io.th0rgal.oraxen.items.ItemBuilder;
|
||||
import io.th0rgal.oraxen.items.OraxenItems;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class OraxenHook implements ItemHook {
|
||||
|
||||
public static final String ID = "ORAXEN";
|
||||
private static final String IDENTIFIER = "oraxen";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(final String id) {
|
||||
final ItemBuilder itemBuilder = OraxenItems.getItemById(id);
|
||||
if (itemBuilder == null) {
|
||||
return null;
|
||||
}
|
||||
return itemBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package io.github.fisher2911.hmccosmetics.hook.item;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import io.github.fisher2911.hmccosmetics.message.Translation;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PAPIExpansion extends PlaceholderExpansion {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UserManager userManager;
|
||||
private static final String IDENTIFIER = "hmccosmetics";
|
||||
private static final String AUTHOR = "MasterOfTheFish";
|
||||
|
||||
public PAPIExpansion(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return AUTHOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return this.plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String onPlaceholderRequest(final Player player, @NotNull final String params) {
|
||||
final String[] parts = params.split("_");
|
||||
if (parts.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (optionalUser.isEmpty()) return null;
|
||||
final User user = optionalUser.get();
|
||||
|
||||
// %hmccosmetics_using_id%
|
||||
if (parts[0].equalsIgnoreCase("using")) {
|
||||
if (parts.length < 2) return null;
|
||||
final String id = this.getId(parts, 1);
|
||||
for (final ArmorItem item : user.getPlayerArmor().getArmorItems()) {
|
||||
if (item.getId().equals(id)) return Translation.translate(Translation.TRUE);
|
||||
}
|
||||
return Translation.translate(Translation.FALSE);
|
||||
}
|
||||
|
||||
// %hmccosmetics_current_type%
|
||||
if (parts[0].equals("current")) {
|
||||
if (parts.length >= 2) {
|
||||
final String typeStr = getId(parts, 1);
|
||||
try {
|
||||
final ArmorItem.Type type = ArmorItem.Type.valueOf(typeStr.toUpperCase());
|
||||
for (final ArmorItem item : user.getPlayerArmor().getArmorItems()) {
|
||||
if (item.getType().equals(type)) return item.getId();
|
||||
}
|
||||
return Translation.translate(Translation.NONE);
|
||||
} catch (final IllegalArgumentException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getId(final String[] parts, final int fromIndex) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = fromIndex; i < parts.length; i++) {
|
||||
builder.append(parts[i]);
|
||||
if (i < parts.length - 1) builder.append("_");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package io.github.fisher2911.hmccosmetics.inventory;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerArmor {
|
||||
|
||||
private final Map<ArmorItem.Type, ArmorItem> armorItems;
|
||||
|
||||
public PlayerArmor(ArmorItem hat, final ArmorItem backpack, final ArmorItem offHand) {
|
||||
this.armorItems = new EnumMap<>(ArmorItem.Type.class);
|
||||
this.armorItems.put(hat.getType(), hat);
|
||||
this.armorItems.put(backpack.getType(), hat);
|
||||
this.armorItems.put(offHand.getType(), offHand);
|
||||
}
|
||||
|
||||
public PlayerArmor(final Map<ArmorItem.Type, ArmorItem> armorItems) {
|
||||
this.armorItems = armorItems;
|
||||
}
|
||||
|
||||
public static PlayerArmor empty() {
|
||||
return new PlayerArmor(
|
||||
ArmorItem.empty(ArmorItem.Type.HAT),
|
||||
ArmorItem.empty(ArmorItem.Type.BACKPACK),
|
||||
ArmorItem.empty(ArmorItem.Type.OFF_HAND)
|
||||
);
|
||||
}
|
||||
|
||||
public ArmorItem getHat() {
|
||||
return this.getItem(ArmorItem.Type.HAT);
|
||||
}
|
||||
|
||||
public ArmorItem getBackpack() {
|
||||
return this.getItem(ArmorItem.Type.BACKPACK);
|
||||
}
|
||||
|
||||
public ArmorItem getOffHand() {
|
||||
return this.getItem(ArmorItem.Type.OFF_HAND);
|
||||
}
|
||||
|
||||
public ArmorItem getItem(final ArmorItem.Type type) {
|
||||
ArmorItem armorItem = this.armorItems.get(type);
|
||||
if (armorItem == null) {
|
||||
armorItem = ArmorItem.empty(type);
|
||||
this.armorItems.put(type, armorItem);
|
||||
}
|
||||
return armorItem;
|
||||
}
|
||||
|
||||
public ArmorItem setItem(final ArmorItem armorItem) {
|
||||
return this.armorItems.put(armorItem.getType(), armorItem);
|
||||
}
|
||||
|
||||
public Collection<ArmorItem> getArmorItems() {
|
||||
return this.armorItems.values();
|
||||
}
|
||||
|
||||
public PlayerArmor copy() {
|
||||
return new PlayerArmor(new HashMap<>(this.armorItems));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (final ArmorItem.Type type : ArmorItem.Type.values()) {
|
||||
this.setItem(ArmorItem.empty(type));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package io.github.fisher2911.hmccosmetics.listener;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
|
||||
public class ClickListener implements Listener {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UserManager userManager;
|
||||
|
||||
public ClickListener(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCosmeticClick(final InventoryClickEvent event) {
|
||||
final HumanEntity player = event.getWhoClicked();
|
||||
if (!(player instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
this.fixInventory((Player) player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCosmeticClick(final InventoryDragEvent event) {
|
||||
final HumanEntity player = event.getWhoClicked();
|
||||
if (!(player instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
this.fixInventory((Player) player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(final InventoryCloseEvent event) {
|
||||
final HumanEntity player = event.getPlayer();
|
||||
this.userManager.get(player.getUniqueId()).ifPresent(this::doRunnable);
|
||||
}
|
||||
|
||||
private void fixInventory(final Player player) {
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (optionalUser.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.doRunnable(optionalUser.get());
|
||||
}
|
||||
|
||||
private void doRunnable(final User user) {
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(
|
||||
this.plugin, () -> this.userManager.updateCosmetics(user),
|
||||
1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.github.fisher2911.hmccosmetics.listener;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.spigotmc.event.entity.EntityMountEvent;
|
||||
|
||||
public class CosmeticFixListener implements Listener {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UserManager userManager;
|
||||
|
||||
public CosmeticFixListener(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityMount(final EntityMountEvent event) {
|
||||
if (!(event.getEntity() instanceof final Player player)) {
|
||||
return;
|
||||
}
|
||||
this.fixCosmetics(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onOffhandSwap(final PlayerSwapHandItemsEvent event) {
|
||||
final ItemStack offHand = event.getOffHandItem();
|
||||
if (offHand != null && offHand.getType() != Material.AIR) {
|
||||
return;
|
||||
}
|
||||
this.fixCosmetics(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRightClick(final PlayerInteractEvent event) {
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK
|
||||
&& event.getHand() != EquipmentSlot.OFF_HAND) {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
final ItemStack mainHand = event.getPlayer().getInventory().getItemInMainHand();
|
||||
|
||||
if (mainHand.getType().isBlock() && mainHand.getAmount() > 0) {
|
||||
return;
|
||||
}
|
||||
this.userManager.updateCosmetics(player.getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBlockPlace(final BlockPlaceEvent event) {
|
||||
if (event.getHand() != EquipmentSlot.OFF_HAND) {
|
||||
return;
|
||||
}
|
||||
final ItemStack itemStack = event.getItemInHand();
|
||||
|
||||
if (itemStack.getAmount() > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fixCosmetics(event.getPlayer());
|
||||
}
|
||||
|
||||
private void fixCosmetics(final Player player) {
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin,
|
||||
() -> this.userManager.updateCosmetics(player.getUniqueId()), 2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package io.github.fisher2911.hmccosmetics.listener;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.config.WardrobeSettings;
|
||||
import io.github.fisher2911.hmccosmetics.database.Database;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class JoinListener implements Listener {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final Database database;
|
||||
private final UserManager userManager;
|
||||
|
||||
public JoinListener(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.database = this.plugin.getDatabase();
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(final PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
this.database.loadUser(player.getUniqueId(),
|
||||
user -> Bukkit.getScheduler().runTaskAsynchronously(this.plugin,
|
||||
() -> {
|
||||
this.userManager.resendCosmetics(player);
|
||||
final WardrobeSettings settings = this.plugin.getSettings().getWardrobeSettings();
|
||||
if (settings.isAlwaysDisplay() && settings.getLocation() != null) {
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
wardrobe.setCurrentLocation(settings.getLocation());
|
||||
wardrobe.spawnFakePlayer(player);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(final PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
optionalUser.ifPresent(user -> {
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
|
||||
if (wardrobe.isActive()) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(
|
||||
this.plugin,
|
||||
() -> wardrobe.despawnFakePlayer(player)
|
||||
);
|
||||
}
|
||||
});
|
||||
this.userManager.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package io.github.fisher2911.hmccosmetics.listener;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.message.Messages;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import io.github.fisher2911.hmccosmetics.user.Wardrobe;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class PlayerShiftListener implements Listener {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UserManager userManager;
|
||||
|
||||
public PlayerShiftListener(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = this.plugin.getUserManager();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerShift(final PlayerToggleSneakEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final Optional<User> userOptional = this.userManager.get(player.getUniqueId());
|
||||
|
||||
if (userOptional.isEmpty()) return;
|
||||
|
||||
final User user = userOptional.get();
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
|
||||
if (!wardrobe.isActive()) return;
|
||||
|
||||
wardrobe.despawnFakePlayer(player);
|
||||
this.plugin.getMessageHandler().sendMessage(
|
||||
player,
|
||||
Messages.CLOSED_WARDROBE
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,13 @@ package io.github.fisher2911.hmccosmetics.listener;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.user.User;
|
||||
import io.github.fisher2911.hmccosmetics.user.UserManager;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class RespawnListener implements Listener {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
@@ -26,8 +25,12 @@ public class RespawnListener implements Listener {
|
||||
Bukkit.getScheduler().runTaskLater(this.plugin, () -> {
|
||||
final Player player = event.getPlayer();
|
||||
final Optional<User> optionalUser = this.userManager.get(player.getUniqueId());
|
||||
|
||||
optionalUser.ifPresent(user -> user.setHat(user.getPlayerArmor().getHat(), this.userManager));
|
||||
optionalUser.ifPresent(user -> {
|
||||
user.despawnAttached();
|
||||
this.userManager.updateCosmetics(user);
|
||||
this.userManager.setItem(user, user.getPlayerArmor().getHat());
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,8 +34,12 @@ public class Message {
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Message message = (Message) o;
|
||||
return Objects.equals(key, message.key);
|
||||
}
|
||||
@@ -48,10 +52,9 @@ public class Message {
|
||||
public enum Type {
|
||||
|
||||
MESSAGE,
|
||||
|
||||
ACTION_BAR,
|
||||
|
||||
TITLE
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
package io.github.fisher2911.hmccosmetics.message;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.util.StringUtils;
|
||||
import io.github.fisher2911.hmccosmetics.util.Utils;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MessageHandler {
|
||||
|
||||
@@ -40,20 +41,22 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sender receiver of message
|
||||
* @param key message key
|
||||
* @param placeholders placeholders
|
||||
*/
|
||||
|
||||
public void sendMessage(final CommandSender sender, final Message key, final Map<String, String> placeholders) {
|
||||
final String message = StringUtils.applyPlaceholders(this.getMessage(key), placeholders);
|
||||
final Component component = Adventure.MINI_MESSAGE.parse(message);
|
||||
this.adventure.sender(sender).sendMessage(component);
|
||||
public void sendMessage(final CommandSender sender, final Message key,
|
||||
final Map<String, String> placeholders) {
|
||||
final String message = this.getPapiPlaceholders(
|
||||
sender,
|
||||
Placeholder.applyPlaceholders(this.getMessage(key), placeholders)
|
||||
);
|
||||
final Component component = Adventure.MINI_MESSAGE.deserialize(message);
|
||||
sender.spigot().sendMessage(BungeeComponentSerializer.get().serialize(component));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sender receiver of message
|
||||
* @param key message key
|
||||
*/
|
||||
@@ -63,20 +66,22 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player receiver of message
|
||||
* @param key message key
|
||||
* @param placeholders placeholders
|
||||
*/
|
||||
|
||||
public void sendActionBar(final Player player, final Message key, final Map<String, String> placeholders) {
|
||||
final String message = StringUtils.applyPlaceholders(this.getMessage(key), placeholders);
|
||||
Component component = Adventure.MINI_MESSAGE.parse(message);
|
||||
this.adventure.player(player).sendActionBar(component);
|
||||
public void sendActionBar(final Player player, final Message key,
|
||||
final Map<String, String> placeholders) {
|
||||
final String message = this.getPapiPlaceholders(
|
||||
player,
|
||||
Placeholder.applyPlaceholders(this.getMessage(key), placeholders)
|
||||
);
|
||||
Component component = Adventure.MINI_MESSAGE.deserialize(message);
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, BungeeComponentSerializer.get().serialize(component));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player receiver of message
|
||||
* @param key message key
|
||||
*/
|
||||
@@ -86,20 +91,22 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player receiver of message
|
||||
* @param key message key
|
||||
* @param placeholders placeholders
|
||||
*/
|
||||
|
||||
public void sendTitle(final Player player, final Message key, final Map<String, String> placeholders) {
|
||||
final String message = StringUtils.applyPlaceholders(this.getMessage(key), placeholders);
|
||||
Component component = Adventure.MINI_MESSAGE.parse(message);
|
||||
public void sendTitle(final Player player, final Message key,
|
||||
final Map<String, String> placeholders) {
|
||||
final String message = this.getPapiPlaceholders(
|
||||
player,
|
||||
Placeholder.applyPlaceholders(this.getMessage(key), placeholders)
|
||||
);
|
||||
Component component = Adventure.MINI_MESSAGE.deserialize(message);
|
||||
this.adventure.player(player).showTitle(Title.title(component, Component.empty()));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player receiver of message
|
||||
* @param key message key
|
||||
*/
|
||||
@@ -109,7 +116,6 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key message key
|
||||
* @return message, or empty string if message not found
|
||||
*/
|
||||
@@ -140,19 +146,27 @@ public class MessageHandler {
|
||||
}
|
||||
|
||||
for (final String key : config.getKeys(false)) {
|
||||
|
||||
final String message = Utils.replaceIfNull(config.getString(key), "", value -> {
|
||||
if (value == null) {
|
||||
this.logger.warning(String.format(ErrorMessages.ITEM_NOT_FOUND, "message", fileName));
|
||||
this.logger.warning(
|
||||
String.format(ErrorMessages.ITEM_NOT_FOUND, "message", fileName));
|
||||
}
|
||||
}).replace(Placeholder.PREFIX, prefix);
|
||||
|
||||
final Message.Type messageType = Utils.stringToEnum(
|
||||
Utils.replaceIfNull(config.getString("type"), "")
|
||||
, Message.Type.class, Message.Type.MESSAGE
|
||||
Utils.replaceIfNull(config.getString("type"), ""), Message.Type.class,
|
||||
Message.Type.MESSAGE
|
||||
);
|
||||
|
||||
this.messageMap.put(key, new Message(key, message, messageType));
|
||||
}
|
||||
}
|
||||
|
||||
private String getPapiPlaceholders(final CommandSender sender, final String message) {
|
||||
if (sender instanceof final Player player) {
|
||||
return Placeholder.applyPapiPlaceholders(player, message);
|
||||
}
|
||||
return Placeholder.applyPapiPlaceholders(null, message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package io.github.fisher2911.hmccosmetics.message;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class Messages {
|
||||
|
||||
public static final Message INVALID_COLOR = new Message(
|
||||
"","<red>" + Placeholder.ITEM + " is an invalid color.");
|
||||
public static final Message NO_PERMISSION =
|
||||
new Message("no-permission", "You do not have permission for this!");
|
||||
public static final Message NO_COSMETIC_PERMISSION =
|
||||
new Message("no-cosmetic-permission", "You do not have permission for this cosmetic!");
|
||||
public static final Message SET_HAT =
|
||||
new Message("set-hat", "Set hat");
|
||||
public static final Message REMOVED_HAT =
|
||||
new Message("removed-hat", "Removed hat");
|
||||
public static final Message SET_BACKPACK =
|
||||
new Message("set-backpack", "Set backpack");
|
||||
public static final Message REMOVED_BACKPACK =
|
||||
new Message("removed-backpack", "Removed backpack");
|
||||
public static final Message SET_OFF_HAND =
|
||||
new Message("set-off-hand", "Set off hand");
|
||||
public static final Message REMOVED_OFF_HAND =
|
||||
new Message("removed-off-hand", "Removed off hand");
|
||||
public static final Message SET_DYE_COLOR =
|
||||
new Message("set-dye-color", "Set dye color of " + Placeholder.ITEM);
|
||||
public static final Message MUST_BE_PLAYER =
|
||||
new Message("must-be-player", "You must be a player to do this!");
|
||||
public static final Message RELOADED =
|
||||
new Message("reloaded", "Config reloaded");
|
||||
public static final Message INVALID_TYPE =
|
||||
new Message("invalid-type", "Invalid type");
|
||||
public static final Message INVALID_USER =
|
||||
new Message("invalid-user", ChatColor.RED + "That user's data cannot be found!");
|
||||
public static final Message ITEM_NOT_FOUND =
|
||||
new Message("item-not-found", ChatColor.RED + "That item could not be found!");
|
||||
public static final Message HELP_COMMAND =
|
||||
new Message("help-command",
|
||||
"""
|
||||
<#6D9DC5><st> </st> <gradient:#40B7D6:#6D9DC5>HMCCosmetics - Help</gradient><#6D9DC5> <st> </st>
|
||||
|
||||
|
||||
<#5AE4B5>• <#40B7D6>/cosmetics - <#6D9DC5>Opens cosmetics GUI.
|
||||
|
||||
<#5AE4B5>• <#40B7D6>/cosmetics dye <gray><BACKPACK/HAT></gray> - <#6D9DC5>Opens dye menu for specified cosmetic.
|
||||
|
||||
<#5AE4B5>• <#40B7D6>/cosmetics help - <#6D9DC5>Opens this menu.
|
||||
|
||||
|
||||
<st> </st>""");
|
||||
|
||||
public static final Message OPENED_WARDROBE =
|
||||
new Message("opened-wardrobe", ChatColor.GREEN + "Viewing wardrobe!");
|
||||
public static final Message CLOSED_WARDROBE =
|
||||
new Message("closed-wardrobe", ChatColor.GREEN + "Closing wardrobe!");
|
||||
public static final Message WARDROBE_ALREADY_OPEN =
|
||||
new Message("wardrobe-already-open", ChatColor.RED + "The wardrobe is already open!");
|
||||
public static final Message NOT_NEAR_WARDROBE =
|
||||
new Message("not-near-wardrobe", ChatColor.RED + "You are not near the wardrobe!");
|
||||
public static final Message CANNOT_USE_PORTABLE_WARDROBE =
|
||||
new Message("cannot-use-portable-wardrobe", ChatColor.RED + "You cannot use the portable wardrobe!");
|
||||
public static final Message OPENED_OTHER_WARDROBE =
|
||||
new Message("opened-other-wardrobe", ChatColor.GREEN + "Opening " + Placeholder.PLAYER + "'s wardrobe.");
|
||||
|
||||
public static final Message SET_OTHER_BACKPACK = new Message(
|
||||
"set-other-backpack", ChatColor.GREEN + "You have set the backpack of " +
|
||||
Placeholder.PLAYER + " to " + Placeholder.TYPE + "."
|
||||
);
|
||||
public static final Message SET_OTHER_HAT = new Message(
|
||||
"set-other-backpack", ChatColor.GREEN + "You have set the helmet of " +
|
||||
Placeholder.PLAYER + " to " + Placeholder.TYPE + "."
|
||||
);
|
||||
public static final Message SET_OTHER_OFF_HAND = new Message(
|
||||
"set-other-off-hand", ChatColor.GREEN + "You have set the off hand of " +
|
||||
Placeholder.PLAYER + " to " + Placeholder.TYPE + "."
|
||||
);
|
||||
|
||||
public static Message getSetMessage(final ArmorItem.Type type) {
|
||||
return switch (type) {
|
||||
case HAT -> Messages.SET_HAT;
|
||||
case BACKPACK -> Messages.SET_BACKPACK;
|
||||
case OFF_HAND -> Messages.SET_OFF_HAND;
|
||||
};
|
||||
}
|
||||
|
||||
public static Message getRemovedMessage(final ArmorItem.Type type) {
|
||||
return switch (type) {
|
||||
case HAT -> Messages.REMOVED_HAT;
|
||||
case BACKPACK -> Messages.REMOVED_BACKPACK;
|
||||
case OFF_HAND -> Messages.REMOVED_OFF_HAND;
|
||||
};
|
||||
}
|
||||
|
||||
public static Message getSetOtherMessage(final ArmorItem.Type type) {
|
||||
return switch (type) {
|
||||
case HAT -> Messages.SET_OTHER_HAT;
|
||||
case BACKPACK -> Messages.SET_OTHER_BACKPACK;
|
||||
case OFF_HAND -> Messages.SET_OTHER_OFF_HAND;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.github.fisher2911.hmccosmetics.message;
|
||||
|
||||
public class Permission {
|
||||
|
||||
public static final String DEFAULT_COMMAND = "hmccosmetics.cmd.default";
|
||||
public static final String DYE_COMMAND = "hmccosmetics.cmd.dye";
|
||||
public static final String RELOAD_COMMAND = "hmccosmetics.cmd.reload";
|
||||
public static final String HELP_COMMAND = "hmccosmetics.cmd.help";
|
||||
public static final String SET_COSMETIC_COMMAND = "hmccosmetics.cmd.set";
|
||||
public static final String PORTABLE_WARDROBE = "hmccosmetics.cmd.wardrobe.portable";
|
||||
public static final String WARDROBE = "hmccosmetics.cmd.wardrobe";
|
||||
public static final String OPEN_OTHER_WARDROBE = "hmccosmetics.cmd.wardrobe.other";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.github.fisher2911.hmccosmetics.message;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.hook.HookManager;
|
||||
import io.github.fisher2911.hmccosmetics.hook.PAPIHook;
|
||||
import java.util.Map;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Placeholder {
|
||||
|
||||
public static final String PREFIX = "%prefix%";
|
||||
public static final String TYPE = "%type%";
|
||||
public static final String ITEM = "%item%";
|
||||
public static final String FILE = "%file%";
|
||||
|
||||
public static final String PLAYER = "%player%";
|
||||
public static final String ENABLED = "%enabled%";
|
||||
public static final String ALLOWED = "%allowed%";
|
||||
|
||||
/**
|
||||
* @param message message being translated
|
||||
* @param placeholders placeholders applied
|
||||
* @return message with placeholders applied
|
||||
*/
|
||||
|
||||
public static String applyPlaceholders(String message, final Map<String, String> placeholders) {
|
||||
for (final Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
message = message.replace(entry.getKey(), Translation.translate(entry.getValue()));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public static String applyPapiPlaceholders(@Nullable final Player player,
|
||||
final String message) {
|
||||
if (HookManager.getInstance().isEnabled(PAPIHook.class)) {
|
||||
return HookManager.getInstance().getPapiHook().parse(player, message);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.github.fisher2911.hmccosmetics.message;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class Translation {
|
||||
|
||||
public static final String TRUE = "true";
|
||||
public static final String FALSE = "false";
|
||||
public static final String NONE = "none";
|
||||
|
||||
private static final Translation INSTANCE;
|
||||
private static final String FILE_NAME = "translations.yml";
|
||||
private static final String TRANSLATION_PATH = "translations";
|
||||
|
||||
static {
|
||||
INSTANCE = new Translation(HMCCosmetics.getPlugin(HMCCosmetics.class));
|
||||
}
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final Map<String, String> translations;
|
||||
|
||||
public Translation(final HMCCosmetics plugin) {
|
||||
this.translations = new HashMap<>();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static Translation getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static String translate(final String key) {
|
||||
return INSTANCE.translations.getOrDefault(key, key);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
final File file = new File(this.plugin.getDataFolder(), FILE_NAME);
|
||||
if (!file.exists()) {
|
||||
this.plugin.saveResource(FILE_NAME, false);
|
||||
}
|
||||
|
||||
final FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
final ConfigurationSection section = config.getConfigurationSection(TRANSLATION_PATH);
|
||||
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final String key : section.getKeys(false)) {
|
||||
this.translations.put(key, section.getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package io.github.fisher2911.hmccosmetics.packet;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import io.github.fisher2911.nms.DestroyPacket;
|
||||
import io.github.fisher2911.nms.DestroyPacket_1_17_R1;
|
||||
import io.github.fisher2911.nms.DestroyPacket_1_18_R1;
|
||||
import io.github.fisher2911.nms.PlayerPackets_1_17_R1;
|
||||
import io.github.fisher2911.nms.PlayerPackets_1_18_R1;
|
||||
import io.github.fisher2911.nms.PlayerPackets;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PacketManager {
|
||||
|
||||
private static final PlayerPackets playerPackets;
|
||||
private static final DestroyPacket destroyPacket;
|
||||
|
||||
static {
|
||||
final String version = Bukkit.getVersion();
|
||||
System.out.println("Version: " + Bukkit.getVersion());
|
||||
if (version.contains("1.17")) {
|
||||
playerPackets = new PlayerPackets_1_17_R1();
|
||||
destroyPacket = new DestroyPacket_1_17_R1();
|
||||
} else if (version.contains("1.18")) {
|
||||
playerPackets = new PlayerPackets_1_18_R1();
|
||||
destroyPacket = new DestroyPacket_1_18_R1();
|
||||
} else {
|
||||
playerPackets = null;
|
||||
destroyPacket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static PacketContainer getEntitySpawnPacket(final Location location, final int entityId,
|
||||
final EntityType entityType) {
|
||||
final PacketContainer packet = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY);
|
||||
|
||||
// Entity ID
|
||||
packet.getIntegers().write(0, entityId);
|
||||
// Entity Type
|
||||
// packet.getIntegers().write(6, 78);
|
||||
// Set yaw pitch
|
||||
packet.getIntegers().write(4, (int) location.getPitch());
|
||||
packet.getIntegers().write(5, (int) location.getYaw());
|
||||
// Set location
|
||||
packet.getDoubles().write(0, location.getX());
|
||||
packet.getDoubles().write(1, location.getY());
|
||||
packet.getDoubles().write(2, location.getZ());
|
||||
// Set UUID
|
||||
packet.getUUIDs().write(0, UUID.randomUUID());
|
||||
|
||||
packet.getEntityTypeModifier().write(0, entityType);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static PacketContainer getEquipmentPacket(
|
||||
final List<Pair<EnumWrappers.ItemSlot, ItemStack>> equipmentList,
|
||||
final int entityId
|
||||
) {
|
||||
|
||||
final PacketContainer armorPacket = new PacketContainer(
|
||||
PacketType.Play.Server.ENTITY_EQUIPMENT);
|
||||
armorPacket.getIntegers().write(0, entityId);
|
||||
armorPacket.getSlotStackPairLists().write(0, equipmentList);
|
||||
|
||||
return armorPacket;
|
||||
}
|
||||
|
||||
public static PacketContainer getRotationPacket(final int entityId, final Location location) {
|
||||
final PacketContainer rotationPacket = new PacketContainer(
|
||||
PacketType.Play.Server.ENTITY_HEAD_ROTATION);
|
||||
|
||||
rotationPacket.getIntegers().write(0, entityId);
|
||||
rotationPacket.getBytes().write(0, (byte) (location.getYaw() * 256 / 360));
|
||||
|
||||
return rotationPacket;
|
||||
}
|
||||
|
||||
public static PacketContainer getRidingPacket(final int mountId, final int passengerId) {
|
||||
final PacketContainer ridingPacket = new PacketContainer(PacketType.Play.Server.MOUNT);
|
||||
ridingPacket.
|
||||
getIntegers().
|
||||
write(0, mountId);
|
||||
ridingPacket.getIntegerArrays().write(0, new int[]{passengerId});
|
||||
|
||||
return ridingPacket;
|
||||
}
|
||||
|
||||
public static PacketContainer getEntityDestroyPacket(final int entityId) {
|
||||
return destroyPacket.get(entityId);
|
||||
}
|
||||
|
||||
public static PacketContainer getSoundPacket(
|
||||
final Player player,
|
||||
final Location location,
|
||||
final MinecraftKey name,
|
||||
final float volume,
|
||||
final float pitch,
|
||||
final EnumWrappers.SoundCategory soundCategory
|
||||
) {
|
||||
final var manager = ProtocolLibrary.getProtocolManager();
|
||||
final var packet = manager.createPacket(PacketType.Play.Server.CUSTOM_SOUND_EFFECT);
|
||||
|
||||
packet.getMinecraftKeys()
|
||||
.write(
|
||||
0,
|
||||
name
|
||||
);
|
||||
|
||||
packet.getSoundCategories()
|
||||
.write(0, EnumWrappers.SoundCategory.valueOf(soundCategory.name()));
|
||||
|
||||
packet.getIntegers()
|
||||
.write(0, location.getBlockX() * 8)
|
||||
.write(
|
||||
1, location.getBlockY() * 8
|
||||
)
|
||||
.write(2, location.getBlockZ() * 8);
|
||||
|
||||
packet.getFloat()
|
||||
.write(0, volume)
|
||||
.write(1, pitch);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static PacketContainer getFakePlayerSpawnPacket(final Location location, final UUID uuid, final int entityId) throws IllegalStateException {
|
||||
if (playerPackets == null) throw new IllegalStateException("This cannot be used in version: " + Bukkit.getVersion());
|
||||
return playerPackets.getSpawnPacket(location, uuid, entityId);
|
||||
}
|
||||
|
||||
public static PacketContainer getFakePlayerInfoPacket(final Player player, final UUID uuid) throws IllegalStateException {
|
||||
if (playerPackets == null) throw new IllegalStateException("This cannot be used in version: " + Bukkit.getVersion());
|
||||
return playerPackets.getPlayerInfoPacket(player, uuid);
|
||||
}
|
||||
|
||||
public static PacketContainer getRemovePlayerPacket(final Player player, final UUID uuid, final int entityId) {
|
||||
if (playerPackets == null) throw new IllegalStateException("This cannot be used in version: " + Bukkit.getVersion());
|
||||
return playerPackets.getRemovePacket(player, uuid, entityId);
|
||||
}
|
||||
|
||||
public static void sendPacket(final Player to, final PacketContainer... packets) {
|
||||
final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
try {
|
||||
for (final PacketContainer packet : packets) {
|
||||
protocolManager.sendServerPacket(to, packet);
|
||||
}
|
||||
} catch (final InvocationTargetException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendPacketToOnline(final PacketContainer... packets) {
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
sendPacket(player, packets);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.github.fisher2911.hmccosmetics.user;
|
||||
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Equipment {
|
||||
|
||||
private static final EquipmentSlot[] VALUES = EquipmentSlot.values();
|
||||
private final Map<EquipmentSlot, ItemStack> equipment = new EnumMap<>(EquipmentSlot.class);
|
||||
|
||||
public Equipment() {
|
||||
}
|
||||
|
||||
public static Equipment fromEntityEquipment(final EntityEquipment entityEquipment) {
|
||||
final Equipment equipment = new Equipment();
|
||||
for (final EquipmentSlot slot : VALUES) {
|
||||
equipment.setItem(slot, entityEquipment.getItem(slot));
|
||||
}
|
||||
return equipment;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItem(final EquipmentSlot slot) {
|
||||
return this.equipment.get(slot);
|
||||
}
|
||||
|
||||
public void setItem(final EquipmentSlot slot, @Nullable final ItemStack itemStack) {
|
||||
this.equipment.put(slot, itemStack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package io.github.fisher2911.hmccosmetics.user;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import io.github.fisher2911.hmccosmetics.config.Settings;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class User {
|
||||
|
||||
private final UUID uuid;
|
||||
private final PlayerArmor playerArmor;
|
||||
|
||||
protected Wardrobe wardrobe;
|
||||
|
||||
private ArmorItem lastSetItem = ArmorItem.empty(ArmorItem.Type.HAT);
|
||||
|
||||
private boolean hasArmorStand;
|
||||
private final int armorStandId;
|
||||
|
||||
public User(final UUID uuid, final PlayerArmor playerArmor, final Wardrobe wardrobe, final int armorStandId) {
|
||||
this.uuid = uuid;
|
||||
this.playerArmor = playerArmor;
|
||||
this.wardrobe = wardrobe;
|
||||
this.armorStandId = armorStandId;
|
||||
}
|
||||
|
||||
protected User(final UUID uuid, final PlayerArmor playerArmor, final int armorStandId) {
|
||||
this.uuid = uuid;
|
||||
this.playerArmor = playerArmor;
|
||||
this.armorStandId = armorStandId;
|
||||
}
|
||||
|
||||
public @Nullable Player getPlayer() {
|
||||
return Bukkit.getPlayer(this.uuid);
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public PlayerArmor getPlayerArmor() {
|
||||
return playerArmor;
|
||||
}
|
||||
|
||||
public Wardrobe getWardrobe() {
|
||||
return wardrobe;
|
||||
}
|
||||
|
||||
protected void setPlayerArmor(final PlayerArmor playerArmor) {
|
||||
for (final ArmorItem armorItem : playerArmor.getArmorItems()) {
|
||||
this.playerArmor.setItem(armorItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeAllCosmetics() {
|
||||
for (final ArmorItem.Type type : ArmorItem.Type.values()) {
|
||||
this.removeItem(type);
|
||||
}
|
||||
}
|
||||
|
||||
public int getArmorStandId() {
|
||||
return armorStandId;
|
||||
}
|
||||
|
||||
protected ArmorItem setItem(final ArmorItem armorItem) {
|
||||
this.lastSetItem = armorItem;
|
||||
return this.playerArmor.setItem(armorItem);
|
||||
}
|
||||
|
||||
protected ArmorItem removeItem(final ArmorItem.Type type) {
|
||||
return this.setItem(ArmorItem.empty(type));
|
||||
}
|
||||
|
||||
public void spawnArmorStand(final Player other, final Location location) {
|
||||
final PacketContainer packet = PacketManager.getEntitySpawnPacket(location, this.armorStandId, EntityType.ARMOR_STAND);
|
||||
|
||||
PacketManager.sendPacket(other, packet);
|
||||
}
|
||||
|
||||
public void spawnArmorStand(final Settings settings) {
|
||||
if (this.hasArmorStand) {
|
||||
this.updateArmorStand(settings);
|
||||
return;
|
||||
}
|
||||
|
||||
final Player player = this.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
for (final Player p : Bukkit.getOnlinePlayers()) {
|
||||
this.spawnArmorStand(p, player.getLocation());
|
||||
}
|
||||
|
||||
this.hasArmorStand = true;
|
||||
}
|
||||
|
||||
public void updateArmorStand(final Settings settings) {
|
||||
if (!this.hasArmorStand) {
|
||||
this.spawnArmorStand(settings);
|
||||
}
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
this.updateArmorStand(player, settings);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateArmorStand(final Player other, final Settings settings) {
|
||||
final Player player = this.getPlayer();
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
this.updateArmorStand(other, settings, player.getLocation());
|
||||
}
|
||||
|
||||
public void updateArmorStand(final Player other, final Settings settings, final Location location) {
|
||||
final List<Pair<EnumWrappers.ItemSlot, ItemStack>> equipmentList = new ArrayList<>();
|
||||
final boolean hidden = !this.shouldShow(other);
|
||||
if (hidden) {
|
||||
equipmentList.add(new Pair<>(EnumWrappers.ItemSlot.HEAD,
|
||||
new ItemStack(Material.AIR)
|
||||
));
|
||||
} else {
|
||||
equipmentList.add(new Pair<>(EnumWrappers.ItemSlot.HEAD,
|
||||
this.playerArmor.getBackpack().getColored()
|
||||
));
|
||||
}
|
||||
|
||||
final PacketContainer armorPacket = PacketManager.getEquipmentPacket(equipmentList, this.armorStandId);
|
||||
final PacketContainer rotationPacket = PacketManager.getRotationPacket(this.armorStandId, location);
|
||||
final PacketContainer ridingPacket = PacketManager.getRidingPacket(this.getEntityId(), this.armorStandId);
|
||||
|
||||
final PacketContainer metaContainer = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
|
||||
|
||||
WrappedDataWatcher metaData = new WrappedDataWatcher();
|
||||
|
||||
final Serializer byteSerializer = WrappedDataWatcher.Registry.get(Byte.class);
|
||||
|
||||
metaData.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, byteSerializer), (byte) (0x20));
|
||||
metaData.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, byteSerializer), (byte) (0x10));
|
||||
|
||||
metaContainer.getIntegers().write(0, this.armorStandId);
|
||||
metaContainer.getWatchableCollectionModifier().write(0, metaData.getWatchableObjects());
|
||||
|
||||
PacketManager.sendPacket(other, armorPacket, metaContainer, rotationPacket, ridingPacket);
|
||||
|
||||
if (hidden) return;
|
||||
|
||||
final int lookDownPitch = settings.getCosmeticSettings().getLookDownPitch();
|
||||
|
||||
if (lookDownPitch != -1 &&
|
||||
this.isFacingDown(location, lookDownPitch)) {
|
||||
equipmentList.set(0, new Pair<>(EnumWrappers.ItemSlot.HEAD,
|
||||
new ItemStack(Material.AIR)
|
||||
));
|
||||
|
||||
if (!this.uuid.equals(other.getUniqueId())) return;
|
||||
PacketManager.sendPacket(other, PacketManager.getEquipmentPacket(equipmentList, this.armorStandId));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldShow(final Player other) {
|
||||
final Player player = this.getPlayer();
|
||||
return player == null ||
|
||||
(!player.hasPotionEffect(PotionEffectType.INVISIBILITY) &&
|
||||
other.canSee(player) &&
|
||||
!player.isSwimming());
|
||||
}
|
||||
|
||||
private boolean isFacingDown(final Location location, final int pitchLimit) {
|
||||
return location.getPitch() > pitchLimit;
|
||||
}
|
||||
|
||||
public void despawnAttached() {
|
||||
PacketManager.sendPacketToOnline(PacketManager.getEntityDestroyPacket(this.armorStandId));
|
||||
this.hasArmorStand = false;
|
||||
}
|
||||
|
||||
public boolean hasArmorStand() {
|
||||
return hasArmorStand;
|
||||
}
|
||||
|
||||
public ArmorItem getLastSetItem() {
|
||||
return lastSetItem;
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
final Player player = this.getPlayer();
|
||||
if (player == null) return -1;
|
||||
return player.getEntityId();
|
||||
}
|
||||
|
||||
public boolean hasPermissionToUse(final ArmorItem armorItem) {
|
||||
final Player player = this.getPlayer();
|
||||
if (player == null) return false;
|
||||
return player.hasPermission(armorItem.getPermission());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
package io.github.fisher2911.hmccosmetics.user;
|
||||
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.Pair;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.api.CosmeticItem;
|
||||
import io.github.fisher2911.hmccosmetics.api.event.CosmeticChangeEvent;
|
||||
import io.github.fisher2911.hmccosmetics.concurrent.Threads;
|
||||
import io.github.fisher2911.hmccosmetics.config.CosmeticSettings;
|
||||
import io.github.fisher2911.hmccosmetics.config.Settings;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.message.Message;
|
||||
import io.github.fisher2911.hmccosmetics.message.MessageHandler;
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import io.github.fisher2911.hmccosmetics.message.Translation;
|
||||
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
|
||||
import io.github.fisher2911.hmccosmetics.util.builder.ItemBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UserManager {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final Settings settings;
|
||||
private final MessageHandler messageHandler;
|
||||
|
||||
private final Map<UUID, User> userMap = new HashMap<>();
|
||||
private final Map<Integer, User> armorStandIdMap = new HashMap<>();
|
||||
|
||||
private BukkitTask teleportTask;
|
||||
|
||||
public UserManager(final HMCCosmetics plugin) {
|
||||
this.plugin = plugin;
|
||||
this.settings = this.plugin.getSettings();
|
||||
this.messageHandler = this.plugin.getMessageHandler();
|
||||
}
|
||||
|
||||
public void add(final User user) {
|
||||
this.userMap.put(user.getUuid(), user);
|
||||
this.armorStandIdMap.put(user.getArmorStandId(), user);
|
||||
this.updateCosmetics(user);
|
||||
}
|
||||
|
||||
public Optional<User> get(final UUID uuid) {
|
||||
return Optional.ofNullable(this.userMap.get(uuid));
|
||||
}
|
||||
|
||||
public Collection<User> getAll() {
|
||||
return this.userMap.values();
|
||||
}
|
||||
|
||||
public void remove(final UUID uuid) {
|
||||
final User user = this.userMap.remove(uuid);
|
||||
|
||||
if (user == null) return;
|
||||
|
||||
this.armorStandIdMap.remove(user.getArmorStandId());
|
||||
|
||||
final PlayerArmor copy = user.getPlayerArmor().copy();
|
||||
|
||||
user.removeAllCosmetics();
|
||||
this.updateCosmetics(user);
|
||||
user.despawnAttached();
|
||||
|
||||
user.setPlayerArmor(copy);
|
||||
|
||||
Threads.getInstance().execute(() -> this.plugin.getDatabase().saveUser(user));
|
||||
}
|
||||
|
||||
public void startTeleportTask() {
|
||||
// throws an error on first load of registry if this isn't here
|
||||
WrappedDataWatcher.Registry.get(Byte.class);
|
||||
this.teleportTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||
this.plugin,
|
||||
() -> {
|
||||
for (final User user : this.userMap.values()) {
|
||||
user.updateArmorStand(this.plugin.getSettings());
|
||||
}
|
||||
},
|
||||
1,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
public void resendCosmetics(final Player player) {
|
||||
for (final User user : this.userMap.values()) {
|
||||
final Player p = user.getPlayer();
|
||||
if (p == null) continue;
|
||||
user.spawnArmorStand(player, p.getLocation());
|
||||
this.updateCosmetics(user, player);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCosmetics(final UUID uuid) {
|
||||
this.get(uuid).ifPresent(this::updateCosmetics);
|
||||
|
||||
}
|
||||
|
||||
public void updateCosmetics(final User user) {
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
this.updateCosmetics(user, player);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCosmetics(final User user, final Player other) {
|
||||
final Player player = user.getPlayer();
|
||||
|
||||
final Equipment equipment;
|
||||
if (player == null) {
|
||||
equipment = new Equipment();
|
||||
} else {
|
||||
equipment = Equipment.fromEntityEquipment(player.getEquipment());
|
||||
}
|
||||
|
||||
final PlayerArmor playerArmor = user.getPlayerArmor();
|
||||
|
||||
final List<Pair<EnumWrappers.ItemSlot, ItemStack>> hatList = new ArrayList<>();
|
||||
final List<Pair<EnumWrappers.ItemSlot, ItemStack>> offHandList = new ArrayList<>();
|
||||
|
||||
final boolean hidden = !user.shouldShow(other);
|
||||
|
||||
final ItemStack hat = this.getCosmeticItem(user, equipment, playerArmor.getHat(), EquipmentSlot.HEAD, hidden);
|
||||
hatList.add(new Pair<>(EnumWrappers.ItemSlot.HEAD, hat));
|
||||
final ItemStack offHand = this.getCosmeticItem(user, equipment, playerArmor.getOffHand(), EquipmentSlot.OFF_HAND, hidden);
|
||||
offHandList.add(new Pair<>(EnumWrappers.ItemSlot.OFFHAND, offHand));
|
||||
|
||||
if (!hat.equals(equipment.getItem(EquipmentSlot.HEAD))) {
|
||||
PacketManager.sendPacket(
|
||||
other,
|
||||
PacketManager.getEquipmentPacket(
|
||||
hatList,
|
||||
user.getEntityId()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!offHand.equals(equipment.getItem(EquipmentSlot.OFF_HAND))) {
|
||||
PacketManager.sendPacket(
|
||||
other,
|
||||
PacketManager.getEquipmentPacket(
|
||||
offHandList,
|
||||
user.getEntityId()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack getCosmeticItem(
|
||||
final User user,
|
||||
final Equipment equipment,
|
||||
final ArmorItem armorItem,
|
||||
final EquipmentSlot slot,
|
||||
final boolean hidden) {
|
||||
final CosmeticSettings cosmeticSettings = this.settings.getCosmeticSettings();
|
||||
|
||||
final Map<String, String> placeholders = Map.of(Placeholder.ALLOWED, Translation.TRUE,
|
||||
Placeholder.ENABLED, Translation.TRUE);
|
||||
|
||||
ItemStack itemStack = ItemBuilder.from(armorItem.getColored()).
|
||||
namePlaceholders(placeholders).
|
||||
lorePlaceholders(placeholders).
|
||||
build();
|
||||
|
||||
final boolean isAir = itemStack.getType().isAir();
|
||||
final boolean requireEmpty = cosmeticSettings.requireEmpty(slot);
|
||||
|
||||
if (!isAir && (!requireEmpty || user instanceof Wardrobe) && !hidden) return itemStack;
|
||||
|
||||
if (equipment == null) return itemStack;
|
||||
|
||||
final ItemStack equipped = equipment.getItem(slot);
|
||||
|
||||
if (equipped != null && equipped.getType() != Material.AIR) return equipped;
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public void setItem(final User user, final ArmorItem armorItem) {
|
||||
final Wardrobe wardrobe = user.getWardrobe();
|
||||
final User setUser;
|
||||
if (wardrobe.isActive()) {
|
||||
setUser = wardrobe;
|
||||
} else {
|
||||
setUser = user;
|
||||
}
|
||||
ArmorItem previous = setUser.getPlayerArmor().getItem(armorItem.getType());
|
||||
|
||||
final CosmeticChangeEvent event =
|
||||
new CosmeticChangeEvent(new CosmeticItem(armorItem.copy()), new CosmeticItem(previous.copy()), setUser);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) return;
|
||||
|
||||
setUser.setItem(event.getCosmeticItem().getArmorItem());
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||
switch (armorItem.getType()) {
|
||||
case HAT, OFF_HAND -> this.updateCosmetics(setUser);
|
||||
case BACKPACK -> {
|
||||
if (wardrobe.isActive()) setUser.updateArmorStand(settings);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeItem(final User user, final ArmorItem.Type type) {
|
||||
this.setItem(user, ArmorItem.empty(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param user
|
||||
* @param armorItem
|
||||
* @param removeMessage
|
||||
* @param setMessage
|
||||
* @return the item that was set
|
||||
*/
|
||||
public ArmorItem setOrUnset(
|
||||
final User user,
|
||||
final ArmorItem armorItem,
|
||||
final Message removeMessage,
|
||||
final Message setMessage) {
|
||||
final Player player = user.getPlayer();
|
||||
|
||||
final ArmorItem.Type type = armorItem.getType();
|
||||
|
||||
final ArmorItem empty = ArmorItem.empty(type);
|
||||
|
||||
if (player == null) {
|
||||
return empty;
|
||||
}
|
||||
|
||||
final ArmorItem check = user.getPlayerArmor().getItem(type);
|
||||
|
||||
if (armorItem.getId().equals(check.getId())) {
|
||||
this.setItem(user, ArmorItem.empty(type));
|
||||
|
||||
messageHandler.sendMessage(
|
||||
player,
|
||||
removeMessage
|
||||
);
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
this.setItem(user, armorItem);
|
||||
messageHandler.sendMessage(
|
||||
player,
|
||||
setMessage
|
||||
);
|
||||
return armorItem;
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
for (final var user : this.userMap.values()) {
|
||||
user.despawnAttached();
|
||||
}
|
||||
|
||||
this.userMap.clear();
|
||||
}
|
||||
|
||||
public void cancelTeleportTask() {
|
||||
this.teleportTask.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package io.github.fisher2911.hmccosmetics.user;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.config.Settings;
|
||||
import io.github.fisher2911.hmccosmetics.config.WardrobeSettings;
|
||||
import io.github.fisher2911.hmccosmetics.gui.ArmorItem;
|
||||
import io.github.fisher2911.hmccosmetics.inventory.PlayerArmor;
|
||||
import io.github.fisher2911.hmccosmetics.packet.PacketManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Wardrobe extends User {
|
||||
|
||||
private final HMCCosmetics plugin;
|
||||
private final UUID ownerUUID;
|
||||
private final int entityId;
|
||||
private boolean active;
|
||||
|
||||
private boolean spawned;
|
||||
|
||||
private Location currentLocation;
|
||||
|
||||
public Wardrobe(
|
||||
final HMCCosmetics plugin,
|
||||
final UUID uuid,
|
||||
final UUID ownerUUID,
|
||||
final PlayerArmor playerArmor,
|
||||
final int armorStandId,
|
||||
final int entityId,
|
||||
final boolean active) {
|
||||
super(uuid, playerArmor, armorStandId);
|
||||
this.plugin = plugin;
|
||||
this.ownerUUID = ownerUUID;
|
||||
this.entityId = entityId;
|
||||
this.active = active;
|
||||
this.wardrobe = this;
|
||||
}
|
||||
|
||||
public void spawnFakePlayer(final Player viewer) {
|
||||
final WardrobeSettings settings = this.plugin.getSettings().getWardrobeSettings();
|
||||
if (settings.inDistanceOfStatic(viewer.getLocation())) {
|
||||
this.currentLocation = settings.getLocation();
|
||||
} else if (this.currentLocation == null) {
|
||||
this.currentLocation = viewer.getLocation().clone();
|
||||
this.currentLocation.setPitch(0);
|
||||
this.currentLocation.setYaw(0);
|
||||
} else if (this.spawned) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PacketContainer playerSpawnPacket = PacketManager.getFakePlayerSpawnPacket(
|
||||
this.currentLocation,
|
||||
this.getUuid(),
|
||||
this.entityId
|
||||
);
|
||||
final PacketContainer playerInfoPacket = PacketManager.getFakePlayerInfoPacket(
|
||||
viewer,
|
||||
this.getUuid()
|
||||
);
|
||||
PacketManager.sendPacket(viewer, playerInfoPacket, playerSpawnPacket);
|
||||
this.spawnArmorStand(viewer, this.currentLocation);
|
||||
this.updateArmorStand(viewer, plugin.getSettings(), this.currentLocation);
|
||||
// PacketManager.sendPacket(viewer, PacketManager.getRotationPacket(this.getEntityId(), this.currentLocation));
|
||||
this.spawned = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateArmorStand(final Player player, final Settings settings) {
|
||||
this.updateArmorStand(player, settings, this.currentLocation);
|
||||
}
|
||||
|
||||
public void despawnFakePlayer(final Player viewer) {
|
||||
final WardrobeSettings settings = this.plugin.getSettings().getWardrobeSettings();
|
||||
PacketManager.sendPacket(viewer, PacketManager.getEntityDestroyPacket(this.getEntityId()));
|
||||
this.despawnAttached();
|
||||
this.active = false;
|
||||
this.spawned = false;
|
||||
this.currentLocation = null;
|
||||
this.getPlayerArmor().clear();
|
||||
|
||||
if (settings.isAlwaysDisplay()) {
|
||||
this.currentLocation = settings.getLocation();
|
||||
if (this.currentLocation == null) return;
|
||||
this.spawnFakePlayer(viewer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityId() {
|
||||
return this.entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermissionToUse(final ArmorItem armorItem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(final boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public void setCurrentLocation(final Location currentLocation) {
|
||||
this.currentLocation = currentLocation;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Location getCurrentLocation() {
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Player getPlayer() {
|
||||
return Bukkit.getPlayer(this.ownerUUID);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,12 +8,7 @@ import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public class Keys {
|
||||
|
||||
static HMCCosmetics plugin;
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
static HMCCosmetics plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
public static final NamespacedKey ITEM_KEY = new NamespacedKey(plugin, "cosmetic");
|
||||
public static final NamespacedKey ARMOR_STAND_KEY = new NamespacedKey(plugin, "armor-stand");
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.github.fisher2911.hmccosmetics.util;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.HMCCosmetics;
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
private static final HMCCosmetics plugin;
|
||||
|
||||
static {
|
||||
plugin = HMCCosmetics.getPlugin(HMCCosmetics.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parsed message to be parsed
|
||||
* @return MiniMessage parsed string
|
||||
*/
|
||||
|
||||
public static Component parse(final String parsed) {
|
||||
return Adventure.MINI_MESSAGE.deserialize(parsed);
|
||||
}
|
||||
|
||||
public static String parseStringToString(final String parsed) {
|
||||
return Adventure.SERIALIZER.serialize(Adventure.MINI_MESSAGE.deserialize(parsed));
|
||||
}
|
||||
|
||||
public static String formatArmorItemType(String type) {
|
||||
type = type.toLowerCase();
|
||||
final String[] parts = type.split(" ");
|
||||
|
||||
final String firstPart = parts[0].substring(0, 1).toUpperCase() + parts[0].substring(1);
|
||||
|
||||
if (parts.length == 1) {
|
||||
return firstPart;
|
||||
}
|
||||
|
||||
return firstPart + parts[1].substring(0, 1).toUpperCase() + parts[1].substring(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +1,33 @@
|
||||
package io.github.fisher2911.hmccosmetics.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* @param original Object to be checked if null
|
||||
* @param original Object to be checked if null
|
||||
* @param replacement Object returned if original is null
|
||||
* @return original if not null, otherwise replacement
|
||||
*/
|
||||
|
||||
public static <T> T replaceIfNull(final @Nullable T original, final @NotNull T replacement) {
|
||||
return replaceIfNull(original, replacement, t -> {});
|
||||
return replaceIfNull(original, replacement, t -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param original Object to be checked if null
|
||||
* @param original Object to be checked if null
|
||||
* @param replacement Object returned if original is null
|
||||
* @param consumer accepts the original object, can be used for logging
|
||||
* @return original if not null, otherwise replacement
|
||||
*/
|
||||
|
||||
public static <T> T replaceIfNull(final @Nullable T original, final T replacement, final @NotNull Consumer<T> consumer) {
|
||||
public static <T> T replaceIfNull(final @Nullable T original, final T replacement,
|
||||
final @NotNull Consumer<T> consumer) {
|
||||
if (original == null) {
|
||||
consumer.accept(replacement);
|
||||
return replacement;
|
||||
@@ -37,7 +37,6 @@ public class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param t object being checked
|
||||
* @param consumer accepted if t is not null
|
||||
* @param <T> type
|
||||
@@ -51,14 +50,14 @@ public class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param t object being checked
|
||||
* @param function applied if t is not null
|
||||
* @param <T> type
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static <T> Optional<T> returnIfNotNull(final @Nullable T t, final @NotNull Function<T, T> function) {
|
||||
public static <T> Optional<T> returnIfNotNull(final @Nullable T t,
|
||||
final @NotNull Function<T, T> function) {
|
||||
if (t == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -66,7 +65,6 @@ public class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param enumAsString Enum value as a string to be parsed
|
||||
* @param enumClass enum type enumAsString is to be converted to
|
||||
* @param defaultEnum default value to be returned
|
||||
@@ -74,13 +72,13 @@ public class Utils {
|
||||
*/
|
||||
|
||||
public static <E extends Enum<E>> E stringToEnum(final @NotNull String enumAsString,
|
||||
final @NotNull Class<E> enumClass,
|
||||
E defaultEnum) {
|
||||
return stringToEnum(enumAsString, enumClass, defaultEnum, e -> {});
|
||||
final @NotNull Class<E> enumClass,
|
||||
E defaultEnum) {
|
||||
return stringToEnum(enumAsString, enumClass, defaultEnum, e -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param enumAsString Enum value as a string to be parsed
|
||||
* @param enumClass enum type enumAsString is to be converted to
|
||||
* @param defaultEnum default value to be returned
|
||||
@@ -89,9 +87,9 @@ public class Utils {
|
||||
*/
|
||||
|
||||
public static <E extends Enum<E>> E stringToEnum(final @NotNull String enumAsString,
|
||||
@NotNull final Class<E> enumClass,
|
||||
final E defaultEnum,
|
||||
final @NotNull Consumer<E> consumer) {
|
||||
@NotNull final Class<E> enumClass,
|
||||
final E defaultEnum,
|
||||
final @NotNull Consumer<E> consumer) {
|
||||
try {
|
||||
final E value = Enum.valueOf(enumClass, enumAsString);
|
||||
consumer.accept(value);
|
||||
@@ -7,13 +7,9 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ColorBuilder extends ItemBuilder{
|
||||
public class ColorBuilder extends ItemBuilder {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material ItemStack material
|
||||
*/
|
||||
|
||||
@@ -22,7 +18,6 @@ public class ColorBuilder extends ItemBuilder{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param itemStack ItemStack
|
||||
*/
|
||||
|
||||
@@ -31,7 +26,6 @@ public class ColorBuilder extends ItemBuilder{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material ItemStack material
|
||||
* @return this
|
||||
* @throws IllegalArgumentException thrown if itemStack's type can not change color
|
||||
@@ -45,7 +39,6 @@ public class ColorBuilder extends ItemBuilder{
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param itemStack ItemStack
|
||||
* @return this
|
||||
* @throws IllegalArgumentException thrown if itemStack's type can not change color
|
||||
@@ -59,8 +52,18 @@ public class ColorBuilder extends ItemBuilder{
|
||||
return new ColorBuilder(itemStack);
|
||||
}
|
||||
|
||||
public static boolean canBeColored(final Material material) {
|
||||
return canBeColored(new ItemStack(material));
|
||||
}
|
||||
|
||||
public static boolean canBeColored(final ItemStack itemStack) {
|
||||
final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
|
||||
return (itemMeta instanceof LeatherArmorMeta ||
|
||||
itemMeta instanceof PotionMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param color armor color
|
||||
* @return this
|
||||
*/
|
||||
@@ -75,14 +78,4 @@ public class ColorBuilder extends ItemBuilder{
|
||||
return this;
|
||||
}
|
||||
|
||||
public static boolean canBeColored(final Material material) {
|
||||
return canBeColored(new ItemStack(material));
|
||||
}
|
||||
|
||||
public static boolean canBeColored(final ItemStack itemStack) {
|
||||
final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
|
||||
return (itemMeta instanceof LeatherArmorMeta ||
|
||||
itemMeta instanceof PotionMeta);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,17 @@
|
||||
package io.github.fisher2911.hmccosmetics.util.builder;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.message.Adventure;
|
||||
import io.github.fisher2911.hmccosmetics.util.StringUtils;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import io.github.fisher2911.hmccosmetics.message.Placeholder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
public class ItemBuilder {
|
||||
|
||||
@@ -36,7 +34,8 @@ public class ItemBuilder {
|
||||
|
||||
ItemBuilder(final ItemStack itemStack) {
|
||||
this.material = itemStack.getType();
|
||||
this.itemMeta = itemStack.hasItemMeta() ? itemStack.getItemMeta() : Bukkit.getItemFactory().getItemMeta(this.material);
|
||||
this.itemMeta = itemStack.hasItemMeta() ? itemStack.getItemMeta()
|
||||
: Bukkit.getItemFactory().getItemMeta(this.material);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,14 +79,6 @@ public class ItemBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder name(final Component name) {
|
||||
if (this.itemMeta == null) {
|
||||
return this;
|
||||
}
|
||||
this.itemMeta.displayName(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets placeholders to the item's name
|
||||
*
|
||||
@@ -99,7 +90,7 @@ public class ItemBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
final String name = StringUtils.
|
||||
final String name = Placeholder.
|
||||
applyPlaceholders(this.itemMeta.getDisplayName(), placeholders);
|
||||
this.itemMeta.setDisplayName(name);
|
||||
return this;
|
||||
@@ -138,7 +129,7 @@ public class ItemBuilder {
|
||||
}
|
||||
|
||||
for (final String line : previousLore) {
|
||||
lore.add(StringUtils.applyPlaceholders(
|
||||
lore.add(Placeholder.applyPlaceholders(
|
||||
line, placeholders
|
||||
));
|
||||
}
|
||||
@@ -147,6 +138,44 @@ public class ItemBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder papiPlaceholders(final Player player) {
|
||||
this.lorePapiPlaceholders(player);
|
||||
this.namePapiPlaceholders(player);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void lorePapiPlaceholders(final Player player) {
|
||||
if (this.itemMeta == null) {
|
||||
return;
|
||||
}
|
||||
final List<String> newLore = new ArrayList<>();
|
||||
|
||||
final List<String> lore = this.itemMeta.getLore();
|
||||
|
||||
if (lore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final String line : this.itemMeta.getLore()) {
|
||||
newLore.add(Placeholder.applyPapiPlaceholders(player, line));
|
||||
}
|
||||
|
||||
this.itemMeta.setLore(newLore);
|
||||
}
|
||||
|
||||
private void namePapiPlaceholders(final Player player) {
|
||||
if (this.itemMeta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.itemMeta.setDisplayName(
|
||||
Placeholder.applyPapiPlaceholders(
|
||||
player,
|
||||
this.itemMeta.getDisplayName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param unbreakable whether the ItemStack is unbreakable
|
||||
* @return this
|
||||
@@ -172,16 +201,18 @@ public class ItemBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enchantments enchants to be added to the ItemStack
|
||||
* @param enchantments enchants to be added to the ItemStack
|
||||
* @param ignoreLeveLRestrictions whether to ignore enchantment level restrictions
|
||||
* @return this
|
||||
*/
|
||||
|
||||
public ItemBuilder enchants(final Map<Enchantment, Integer> enchantments, boolean ignoreLeveLRestrictions) {
|
||||
public ItemBuilder enchants(final Map<Enchantment, Integer> enchantments,
|
||||
boolean ignoreLeveLRestrictions) {
|
||||
if (this.itemMeta == null) {
|
||||
return this;
|
||||
}
|
||||
enchantments.forEach((enchantment, level) -> this.itemMeta.addEnchant(enchantment, level, ignoreLeveLRestrictions));
|
||||
enchantments.forEach((enchantment, level) -> this.itemMeta.addEnchant(enchantment, level,
|
||||
ignoreLeveLRestrictions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@ package io.github.fisher2911.hmccosmetics.util.builder;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Some parts taken from https://github.com/TriumphTeam/triumph-gui/blob/master/core/src/main/java/dev/triumphteam/gui/builder/item/SkullBuilder.java
|
||||
*/
|
||||
@@ -23,7 +22,8 @@ public class SkullBuilder extends ItemBuilder {
|
||||
Field field;
|
||||
|
||||
try {
|
||||
final SkullMeta skullMeta = (SkullMeta) new ItemStack(Material.PLAYER_HEAD).getItemMeta();
|
||||
final SkullMeta skullMeta = (SkullMeta) new ItemStack(
|
||||
Material.PLAYER_HEAD).getItemMeta();
|
||||
field = skullMeta.getClass().getDeclaredField("profile");
|
||||
field.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
@@ -36,7 +36,6 @@ public class SkullBuilder extends ItemBuilder {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material The material
|
||||
*/
|
||||
|
||||
@@ -46,6 +45,7 @@ public class SkullBuilder extends ItemBuilder {
|
||||
|
||||
/**
|
||||
* Creates a new SkullBuilder instance
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
|
||||
@@ -55,7 +55,6 @@ public class SkullBuilder extends ItemBuilder {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player skull owner
|
||||
* @return this
|
||||
*/
|
||||
@@ -68,7 +67,6 @@ public class SkullBuilder extends ItemBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param texture skull texture
|
||||
* @return this
|
||||
*/
|
||||
25
common/src/main/resources/config.yml
Normal file
25
common/src/main/resources/config.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
cosmetic-settings:
|
||||
require-empty-helmet: false
|
||||
require-empty-off-hand: true
|
||||
# The pitch the player must look down for the backpack to be removed
|
||||
# Set to -1 for no removal
|
||||
look-down-backpack-remove: 70
|
||||
wardrobe:
|
||||
# if true, the wardrobe will be removed when the player is damaged
|
||||
disable-on-damage: true
|
||||
# removed if player leaves this radius, set to -1 for infinite radius
|
||||
display-radius: -1
|
||||
# if the player can use the wardrobe in other locations
|
||||
portable: false
|
||||
# if the wardrobe should always be displayed in the location below
|
||||
always-display: false
|
||||
# spawn static wardrobe if in this radius of wardrobe-location
|
||||
static-radius: 10
|
||||
# location of static wardrobe, remove for none
|
||||
wardrobe-location:
|
||||
world: "World"
|
||||
x: 0
|
||||
y: 0
|
||||
z: 0
|
||||
yaw: 0
|
||||
pitch: 0
|
||||
8
common/src/main/resources/database.yml
Normal file
8
common/src/main/resources/database.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
# SQLite or MySQL (case-insensitive)
|
||||
type: "sqlite"
|
||||
# The rest of these are only required for MySQL
|
||||
name: "name"
|
||||
username: "username"
|
||||
password: "password"
|
||||
ip: "ip"
|
||||
port: 3306
|
||||
1
common/src/main/resources/database/info.yml
Normal file
1
common/src/main/resources/database/info.yml
Normal file
@@ -0,0 +1 @@
|
||||
version: 2
|
||||
100
common/src/main/resources/menus/dye-menu.yml
Normal file
100
common/src/main/resources/menus/dye-menu.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
title: "<white>"
|
||||
rows: 4
|
||||
gui-type: dye
|
||||
cosmetics-slots:
|
||||
27: HAT
|
||||
28: BACKPACK
|
||||
29: OFF_HAND
|
||||
items:
|
||||
10:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 255
|
||||
green: 255
|
||||
blue: 255
|
||||
name: "<gray>Set to <#FFFFFF>white"
|
||||
set-color:
|
||||
red: 255
|
||||
green: 255
|
||||
blue: 255
|
||||
11:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 190
|
||||
green: 20
|
||||
blue: 20
|
||||
name: "<gray>Set to <#BE1414>red"
|
||||
set-color:
|
||||
red: 190
|
||||
green: 20
|
||||
blue: 20
|
||||
12:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 234
|
||||
green: 92
|
||||
blue: 43
|
||||
name: "<gray>Set to <#EA5C2B>orange"
|
||||
set-color:
|
||||
red: 234
|
||||
green: 92
|
||||
blue: 43
|
||||
13:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 255
|
||||
green: 201
|
||||
blue: 0
|
||||
name: "<gray>Set to <#FFC900>yellow"
|
||||
set-color:
|
||||
red: 255
|
||||
green: 201
|
||||
blue: 0
|
||||
14:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 163
|
||||
green: 218
|
||||
blue: 141
|
||||
name: "<gray>Set to <#A3DA8D>green"
|
||||
set-color:
|
||||
red: 163
|
||||
green: 218
|
||||
blue: 141
|
||||
15:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 55
|
||||
green: 49
|
||||
blue: 181
|
||||
name: "<gray>Set to <#3731B5>blue"
|
||||
set-color:
|
||||
red: 55
|
||||
green: 49
|
||||
blue: 181
|
||||
16:
|
||||
material: LEATHER_HORSE_ARMOR
|
||||
model-data: 1
|
||||
color:
|
||||
red: 137
|
||||
green: 70
|
||||
blue: 166
|
||||
name: "<gray>Set to <#8946A6>purple"
|
||||
set-color:
|
||||
red: 137
|
||||
green: 70
|
||||
blue: 166
|
||||
31:
|
||||
material: PAPER
|
||||
name: "<#F7DCFA>Previous Page"
|
||||
amount: 1
|
||||
model-data: 1
|
||||
action: # See how the action system works on the wiki
|
||||
any:
|
||||
open-menu: main
|
||||
91
common/src/main/resources/menus/main.yml
Normal file
91
common/src/main/resources/menus/main.yml
Normal file
@@ -0,0 +1,91 @@
|
||||
title: "<white>" # GUI Title
|
||||
rows: 5 # Rows in the GUI
|
||||
items:
|
||||
1: # GUI Slot number
|
||||
material: LEATHER_HORSE_ARMOR # Also supports Oraxen items! Format: "oraxen:item_name"
|
||||
name: "<rainbow>Colorful Hat</rainbow>"
|
||||
lore: # Lore displayed when the player owns the item
|
||||
- ""
|
||||
- "<gray>Enabled: <#6D9DC5>%enabled%"
|
||||
- "<gray>Allowed: <#6D9DC5>%allowed%"
|
||||
locked-lore: # Lore displayed when the player does not have the correct permission.
|
||||
- "<red>You do not own this item!"
|
||||
amount: 1
|
||||
model-data: 2 # CustomModelData Number
|
||||
type: HAT
|
||||
dyeable: true # Enables dyeable item feature
|
||||
color: # Sets default color for item. Uses RGB format.
|
||||
red: 5
|
||||
green: 230
|
||||
blue: 100
|
||||
action: # See how the action system works on the wiki
|
||||
any:
|
||||
open-menu: dye-menu
|
||||
permission: "cosmetics.colorful_hat" # Can be anything you want.
|
||||
id: colorful_hat # Internal identifier. Can be anything you want.
|
||||
2:
|
||||
material: PAPER
|
||||
name: "<blue>Backpack"
|
||||
lore:
|
||||
- ""
|
||||
- "<gray>Enabled: <#6D9DC5>%enabled%"
|
||||
- "<gray>Allowed: <#6D9DC5>%allowed%"
|
||||
locked-lore:
|
||||
- "<red>You do not own this item!"
|
||||
amount: 1
|
||||
model-data: 4
|
||||
type: BACKPACK
|
||||
permission: ""
|
||||
id: backpack
|
||||
3:
|
||||
material: PAPER
|
||||
name: "<blue>Lantern Cosmetic"
|
||||
lore:
|
||||
- ""
|
||||
- "<gray>Enabled: <#6D9DC5>%enabled%"
|
||||
- "<gray>Allowed: <#6D9DC5>%allowed%"
|
||||
locked-lore:
|
||||
- "<red>You do not own this item!"
|
||||
amount: 1
|
||||
model-data: 5
|
||||
type: OFF_HAND
|
||||
permission: ""
|
||||
id: lantern_cosmetic
|
||||
4:
|
||||
material: PAPER
|
||||
name: "<blue>Baseball Hat"
|
||||
lore:
|
||||
- ""
|
||||
- "<gray>Enabled: <#6D9DC5>%enabled%"
|
||||
- "<gray>Allowed: <#6D9DC5>%allowed%"
|
||||
locked-lore:
|
||||
- "<red>You do not own this item!"
|
||||
amount: 1
|
||||
model-data: 6
|
||||
type: HAT
|
||||
permission: ""
|
||||
id: baseball_hat
|
||||
37:
|
||||
material: PAPER
|
||||
name: "<#40B7D6>Previous Page"
|
||||
amount: 1
|
||||
model-data: 1
|
||||
action:
|
||||
any:
|
||||
open-menu: menu-2
|
||||
40:
|
||||
material: PAPER
|
||||
name: "<rainbow>Customization Menu</rainbow>"
|
||||
amount: 1
|
||||
model-data: 3
|
||||
action:
|
||||
any:
|
||||
open-menu: dye-menu
|
||||
43:
|
||||
material: PAPER
|
||||
name: "<#40B7D6>Next Page"
|
||||
amount: 1
|
||||
model-data: 2
|
||||
action:
|
||||
any:
|
||||
open-menu: menu-2
|
||||
37
common/src/main/resources/messages.yml
Normal file
37
common/src/main/resources/messages.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
prefix: "<white>"
|
||||
no-permission: "%prefix% <red>No Permission!"
|
||||
no-cosmetic-permission: "%prefix% <red>You do not have permission for this cosmetic!"
|
||||
set-hat: "%prefix% <gradient:#6D9DC5:#45CDE9>Applied hat!"
|
||||
removed-hat: "%prefix% <gradient:#6D9DC5:#45CDE9>Removed hat!"
|
||||
set-backpack: "%prefix% <gradient:#6D9DC5:#45CDE9>Applied backpack!"
|
||||
removed-backpack: "%prefix% <gradient:#6D9DC5:#45CDE9>Removed backpack!"
|
||||
set-off-hand: "%prefix% <gradient:#6D9DC5:#45CDE9>Applied offhand!"
|
||||
removed-off-hand: "%prefix% <gradient:#6D9DC5:#45CDE9>Removed offhand!"
|
||||
set-dye-color: "%prefix% <gradient:#6D9DC5:#45CDE9>Set color of %item%!"
|
||||
must-be-player: "<red>You must be a player to do this!"
|
||||
reloaded: "%prefix% <gradient:#00ff87:#60efff>Config files reloaded!"
|
||||
invalid-type: "%prefix% <red>Invalid cosmetic type, please use <u>hat</u>, <u>backpack</u> or <u>off_hand</u>!"
|
||||
set-other-backpack: "%prefix% <gradient:#6D9DC5:#45CDE9>You have set the backpack of %player% to %type%"
|
||||
set-other-hat: "%prefix% <gradient:#6D9DC5:#45CDE9>You have set the hat of %player% to %type%"
|
||||
set-other-off-hand: "%prefix% <gradient:#6D9DC5:#45CDE9>You have set the off hand of %player% to %type%"
|
||||
opened-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9>Viewing wardrobe!"
|
||||
closed-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9>Closed wardrobe!"
|
||||
wardrobe-already-open: "%prefix% <gradient:#6D9DC5:#45CDE9><red>The wardrobe is already open!"
|
||||
not-near-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9><red>You are not near the wardrobe!"
|
||||
cannot-use-portable-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9><red>You cannot use the portable wardrobe!"
|
||||
opened-other-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9><red>Opening %player%'s wardrobe."
|
||||
help-command: "<#6D9DC5><st> </st> %prefix% <gradient:#40B7D6:#6D9DC5>HMCCosmetics - Help</gradient> %prefix% <#6D9DC5> <st> </st>
|
||||
|
||||
|
||||
<#5AE4B5>- <#40B7D6>/cosmetics - <#6D9DC5>Opens cosmetics GUI.
|
||||
|
||||
<#5AE4B5>- <#40B7D6>/cosmetics add <gray><USERNAME> <ID> (#HEX)</gray> - <#6D9DC5>Adds cosmetic to player.
|
||||
|
||||
<#5AE4B5>- <#40B7D6>/cosmetics remove <gray><USERNAME> <BACKPACK/HAT></gray> - <#6D9DC5>Removes cosmetic from a player.
|
||||
|
||||
<#5AE4B5>- <#40B7D6>/cosmetics dye <gray><BACKPACK/HAT></gray> - <#6D9DC5>Opens dye menu for the specified cosmetic type.
|
||||
|
||||
<#5AE4B5>- <#40B7D6>/cosmetics help - <#6D9DC5>Opens this menu.
|
||||
|
||||
|
||||
<st> </st>"
|
||||
3
common/src/main/resources/translations.yml
Normal file
3
common/src/main/resources/translations.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
translations:
|
||||
true: "true"
|
||||
false: "false"
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
269
gradlew
vendored
269
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright <20> 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions <20>$var<61>, <20>${var}<7D>, <20>${var:-default}<7D>, <20>${var+SET}<7D>,
|
||||
# <20>${var#prefix}<7D>, <20>${var%suffix}<7D>, and <20>$( cmd )<29>;
|
||||
# * compound commands having a testable exit status, especially <20>case<73>;
|
||||
# * various built-in commands including <20>command<6E>, <20>set<65>, and <20>ulimit<69>.
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@@ -106,80 +140,95 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
22
nms/build.gradle.kts
Normal file
22
nms/build.gradle.kts
Normal file
@@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
id("java")
|
||||
}
|
||||
|
||||
//group = "io.github.fisher2911"
|
||||
//version = "1.7.1"
|
||||
//description = "Intuitive, easy-to-use cosmetics plugin, designed for servers using resource packs.\n"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://repo.dmulloy2.net/repository/public/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.mojang:authlib:1.5.25")
|
||||
compileOnly("org.spigotmc:spigot:1.18-R0.1-SNAPSHOT")
|
||||
compileOnly("org.jetbrains:annotations:22.0.0")
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.7.0")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
|
||||
public interface DestroyPacket {
|
||||
|
||||
PacketContainer get(final int entityId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.github.fisher2911.nms;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PlayerPackets {
|
||||
|
||||
PacketContainer getSpawnPacket(final Location location, UUID uuid, final int entityId);
|
||||
PacketContainer getPlayerInfoPacket(final Player player, final UUID uuid);
|
||||
PacketContainer getRemovePacket(final Player player, final UUID uuid, final int entityId);
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
rootProject.name = 'HMCCosmetics'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user