9
0
mirror of https://github.com/HibiscusMC/HMCCosmetics.git synced 2025-12-20 07:29:15 +00:00

Compare commits

..

76 Commits

Author SHA1 Message Date
Boy
74fce41db0 refactor: remove unwanted meta properties 2024-08-01 16:13:42 +02:00
Boy
fb6f402c69 fix: separate metadata to firstPersonMetadata & thirdperson metadata 2024-08-01 15:06:56 +02:00
Boy
ed4803f36b refactor: make itemdisplay metadata configurable 2024-08-01 14:00:05 +02:00
Boy
0041f29ed7 fix: backpacks not showing up for other players 2024-08-01 03:56:33 +02:00
Boy
967668321c feat: disable backpack teleport/rotation and use billboard instead 2024-08-01 03:36:33 +02:00
Boy
1b897c390f feat: basic itemdisplay cosmetic backpack impl 2024-08-01 02:06:09 +02:00
Boy
05c13e8990 fix: swapping hotbar-slot resetting NBT of previous-item 2024-07-22 02:24:59 +02:00
LoJoSho
34b02574b2 feat: add user cosmetic item caching 2024-07-21 11:04:06 -05:00
LoJoSho
f81d350a2e clean: update depends 2024-07-11 21:36:50 -05:00
LoJoSho
be86314daf feat: add none database type 2024-07-11 21:23:51 -05:00
LoJoSho
345f903113 clean: remove duplicate emote folder check 2024-07-11 21:14:54 -05:00
LoJoSho
3cf265f231 feat: customize backpack light emination 2024-07-08 18:03:12 -05:00
LoJoSho
d26e7df2ca Merge remote-tracking branch 'origin/remapped' into remapped 2024-07-02 19:43:17 -05:00
LoJoSho
e5dc3f6774 feat: update to Java 21 2024-07-02 19:42:45 -05:00
LoJoSho
fdc9893a60 Merge pull request #147 from MineInAbyss/tweaks
refactor: make hidden-cosmetics message only show when player has cos…
2024-06-15 21:54:15 -05:00
Boy
e8694076b8 refactor: make hidden-cosmetics message only show when player has cosmetics equipped 2024-06-16 01:11:06 +02:00
LoJoSho
1acf536080 fix: ending wardrobe getting illegal argument (same as previous commit) 2024-06-15 09:41:34 -05:00
LoJoSho
9d3ad0b54b fix: 1.20.6 shooting error illegal arguments on equipment slot update 2024-06-15 08:33:05 -05:00
LoJoSho
0b2ade1598 clean: remove old 1.18.2 and 1.19.1/2/3 old packet code 2024-06-14 17:29:03 -05:00
LoJoSho
83651b7250 clean: change our onPlayerLook to onPlayerMove to better describe what it listens to 2024-06-14 17:21:56 -05:00
LoJoSho
6818c09a69 chore: add documentation to CosmeticTypeRegisterEvent 2024-06-14 17:19:46 -05:00
LoJoSho
dc72b677de Merge pull request #144 from MineInAbyss/remapped
feat: Third-party CosmeticTypes, & minor API methods
2024-06-08 17:43:46 -05:00
Boy
5ff1a63eaa feat: add WardrobeManager#lastOpenMenu 2024-06-08 21:30:47 +02:00
LoJoSho
8300a86225 chore: update adventure dependencies 2024-06-08 14:20:21 -05:00
LoJoSho
9e8084194a chore: update triumph gui to 3.1.10 (this was not marked as the latest version) 2024-06-08 14:16:02 -05:00
LoJoSho
c0ea4d5a5b chore: update triumph gui to 3.1.8 2024-06-08 14:15:02 -05:00
Boy
5a963391f8 feat: add locked-equipped-item 2024-06-07 17:36:16 +02:00
Boy
6c4586a6b9 fix: nullpointer due to CUSTOM cosmeticslot 2024-06-07 17:36:16 +02:00
Boy
4cc0a6f968 feat: add CosmeticTypeRegisterEvent to allow for third-party CosmeticTypes 2024-06-07 17:36:16 +02:00
LoJoSho
ab8656ad1a feat: add more logic for dealing with closed connections, closes #140 2024-06-06 19:38:53 -05:00
LoJoSho
ca5e0f96c2 clean: change require-empty in default config to false 2024-06-02 19:58:31 -05:00
LoJoSho
5cddd24097 feat: add HibiscusPlayerEmote events; bumped Hibiscus Commons to 0.4.1 2024-05-29 12:51:21 -05:00
LoJoSho
656e539ae3 feat: add menu clicking cooldown 2024-05-27 21:28:31 -05:00
LoJoSho
862b7c9ee6 fix: Backpacks not appearing after respawning in a different world 2024-05-26 15:31:19 -05:00
LoJoSho
c632174de8 clean: update debug message for menu updateItem 2024-05-24 17:36:34 -05:00
LoJoSho
1e96303765 fix: second NMS check for emotes not updated 2024-05-22 20:20:28 -05:00
LoJoSho
1a6d587ee0 feat: add hidden placeholder 2024-05-22 20:11:02 -05:00
LoJoSho
adcb6de5e4 fix: lang instead of lang3 import for StringUtils 2024-05-22 20:06:03 -05:00
LoJoSho
c36e263a95 feat: bump api version to 1.19 2024-05-22 20:02:16 -05:00
LoJoSho
de1e5bf100 fix: check if entity is null after offhand swap event 2024-05-20 11:09:45 -05:00
LoJoSho
ea25dcf208 fix: dye menu not accepting fireworks 2024-05-20 09:54:11 -05:00
LoJoSho
e3c73d0bfe feat: add firework item effect support 2024-05-19 19:16:53 -05:00
LoJoSho
91b24bfa82 fix: data loading not checking disabled boolean for disabled gamemodes 2024-05-16 20:29:24 -05:00
LoJoSho
28bf5ba2b6 fix: backpacks sometimes still spawned after being hidden 2024-05-15 16:29:09 -05:00
LoJoSho
0249d6abdb fix: player animator attempting to start on 1.20.6 2024-05-12 13:43:51 -05:00
LoJoSho
cb32f635d0 feat: rework of slot options (config reworked for slot options for enchants and showing) 2024-05-11 14:33:46 -05:00
LoJoSho
3bfdde4281 fix: not checking player before checking world 2024-04-30 16:28:31 -05:00
LoJoSho
8daa2709f3 feat: process PAPI placeholders in wardrobe bossbar 2024-04-29 14:32:15 -05:00
LoJoSho
35260d4abb Merge remote-tracking branch 'origin/remapped' into remapped 2024-04-27 09:06:34 -05:00
LoJoSho
2d44435d53 fix: hmccolor dye menu not processing through minimessage 2024-04-27 09:06:21 -05:00
LoJoSho
3d785bd157 version bump (2.7.3-DEV) 2024-04-27 09:04:39 -05:00
lucian929
c33cfbd302 fix: update default config to use proper input slots for color 2024-04-25 15:24:22 -04:00
LoJoSho
f5ed39e02c Merge remote-tracking branch 'origin/remapped' into remapped 2024-04-25 14:09:44 -05:00
LoJoSho
0c3af0e0cd version bump (2.7.2) 2024-04-25 14:09:22 -05:00
lucian929
f5a1a67e1e chore: remove emotes from defaultmenu 2024-04-25 14:13:47 -04:00
LoJoSho
ddc0a504fd fix: disabled worlds not checked if player teleports through portals 2024-04-25 12:12:27 -05:00
LoJoSho
de108753d5 clean: ignore cancelled teleportations 2024-04-02 22:04:40 -05:00
LoJoSho
b31e8b7a4b chore: more documentation for CosmeticUsers class 2024-04-02 22:02:51 -05:00
LoJoSho
383fdfa7f6 fix: no entity + backpack spawning causing NPE 2024-03-16 12:13:07 -05:00
LoJoSho
54e867ab0b Merge pull request #131 from HibiscusMC/allow-flight
fix: wardrobe kicking player if allowFlight not enabled in server.pro…
2024-03-11 08:40:46 -05:00
LoJoSho
068ed3eb70 fix: backpacks not reattaching after teleporting 2024-03-05 22:26:10 -06:00
LoJoSho
a203c60df1 fix: backpacks turning black when under blocks 2024-03-05 10:58:12 -06:00
LoJoSho
e13c3fccb4 fix: hidden flags being added async causing error 2024-02-25 17:51:06 -06:00
LoJoSho
add72e66c9 feat: hidden reasons now in lists, add disableall command (hides all players cosmetics) 2024-02-25 15:20:32 -06:00
LoJoSho
0e587feff0 fix: multiple schedulers when player has multiple loaded cosmetics 2024-02-21 12:42:57 -06:00
LoJoSho
27be86c419 fix: clean resources after sql usage 2024-02-20 13:53:10 -06:00
Boy
3d940d8468 fix: wardrobe kicking player if allowFlight not enabled in server.properties 2024-02-10 13:20:36 +01:00
LoJoSho
7515cdd137 refactor: getHidden to isHidden in CosmeticUser class, deprecate old method 2024-02-04 20:07:01 -06:00
LoJoSho
8e92f3e689 fix: hidden reasons for gamemodes + world not working, spawning entity cosmetics while hidden 2024-02-04 20:04:33 -06:00
LoJoSho
7c4b833d80 fix: tab autocomplete checks attempted before user loading causing NPE 2024-02-04 19:20:37 -06:00
LoJoSho
b291dc4c9f Merge remote-tracking branch 'origin/remapped' into remapped 2024-01-28 10:57:30 -06:00
LoJoSho
60b91df843 fix: balloons with head models pitch being affected by player 2024-01-28 10:56:49 -06:00
LoJoSho
56f380025d fix: equipped armor not showing after exiting wardrobe 2024-01-17 13:07:01 -06:00
LoJoSho
b3e0acbcbd feat: add config options to prevent damage while in the wardrobe 2024-01-17 12:45:04 -06:00
LoJoSho
e2d334db9d version bump (2.7.2-DEV) 2024-01-17 12:25:03 -06:00
LoJoSho
dffcf6213b fix: check if player is not null before running end wardrobe 2024-01-17 12:24:41 -06:00
47 changed files with 1053 additions and 436 deletions

View File

@@ -8,7 +8,7 @@ plugins {
}
group = "com.hibiscusmc"
version = "2.7.1"
version = "2.7.3-DEV"
allprojects {
apply(plugin = "java")
@@ -69,32 +69,33 @@ allprojects {
// Hibiscus Commons
maven("https://repo.hibiscusmc.com/releases")
mavenLocal()
}
dependencies {
compileOnly(fileTree("${project.rootDir}/lib") { include("*.jar") })
compileOnly("com.mojang:authlib:1.5.25")
//compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:24.1.0")
compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0")
compileOnly("me.clip:placeholderapi:2.11.3")
compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.2")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
compileOnly("it.unimi.dsi:fastutil:8.5.11")
compileOnly("org.projectlombok:lombok:1.18.2")
compileOnly("me.lojosho:HibiscusCommons:0.2.2")
compileOnly("it.unimi.dsi:fastutil:8.5.13")
compileOnly("org.projectlombok:lombok:1.18.34")
compileOnly("me.lojosho:HibiscusCommons:0.4.7")
// Handled by Spigot Library Loader
compileOnly("net.kyori:adventure-api:4.15.0")
compileOnly("net.kyori:adventure-text-minimessage:4.15.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.3.2")
compileOnly("net.kyori:adventure-api:4.17.0")
compileOnly("net.kyori:adventure-text-minimessage:4.17.0")
compileOnly("net.kyori:adventure-platform-bukkit:4.3.3")
annotationProcessor("org.projectlombok:lombok:1.18.28")
testCompileOnly("org.projectlombok:lombok:1.18.28")
testAnnotationProcessor("org.projectlombok:lombok:1.18.28")
annotationProcessor("org.projectlombok:lombok:1.18.34")
testCompileOnly("org.projectlombok:lombok:1.18.34")
testAnnotationProcessor("org.projectlombok:lombok:1.18.34")
implementation("dev.triumphteam:triumph-gui:3.1.7") {
implementation("dev.triumphteam:triumph-gui:3.1.10") {
exclude("net.kyori") // Already have adventure API
}
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
@@ -110,7 +111,7 @@ tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
options.release.set(21)
}
javadoc {
@@ -123,7 +124,7 @@ tasks {
}
runServer {
minecraftVersion("1.20.4")
minecraftVersion("1.20.6")
}
shadowJar {
@@ -139,7 +140,7 @@ tasks {
}
doLast {
archiveFile.get().asFile.copyTo(layout.projectDirectory.file("run/plugins/HMCCosmeticsRemapped.jar").asFile, true)
archiveFile.get().asFile.copyTo(File("D:\\Server\\Paper1_21\\plugins\\${project.name}-${project.version}.jar"), true)
println("If you use the plugin, consider buying it for: ")
println("The custom resource pack, Oraxen + ItemAdder configurations, and Discord support!")
println("Polymart: https://polymart.org/resource/1879")
@@ -156,7 +157,7 @@ tasks {
bukkit {
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
main = "com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin"
apiVersion = "1.18"
apiVersion = "1.19"
authors = listOf("LoJoSho")
depend = listOf("HibiscusCommons", "ProtocolLib")
softDepend = listOf("ModelEngine", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen", "MMOItems", "Eco")
@@ -244,10 +245,19 @@ bukkit {
register("hmccosmetics.unapplydeath.bypass") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.disableall") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.hiddenreasons") {
default = BukkitPluginDescription.Permission.Default.OP
}
register("hmccosmetics.cmd.clearhiddenreasons") {
default = BukkitPluginDescription.Permission.Default.OP
}
}
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17
toolchain.languageVersion.set(JavaLanguageVersion.of(21
))
}

View File

@@ -65,12 +65,8 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
if (!Path.of(getDataFolder().getPath() + "/cosmetics/").toFile().exists()) saveResource("cosmetics/defaultcosmetics.yml", false);
if (!Path.of(getDataFolder().getPath() + "/menus/").toFile().exists()) saveResource("menus/defaultmenu.yml", false);
// Emote folder setup
File emoteFile = new File(getDataFolder().getPath() + "/emotes");
if (!emoteFile.exists()) emoteFile.mkdir();
// Player Animator
if (!HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R2") && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R3")) PlayerAnimatorImpl.initialize(this); // PlayerAnimator does not support 1.20.2 yet
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R3") || HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R1")) PlayerAnimatorImpl.initialize(this); // PlayerAnimator does not support 1.20.2 yet
// Configuration Sync
final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile();
@@ -229,7 +225,7 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
}
}
if (Settings.isEmotesEnabled() && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R2") && !HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R3")) EmoteManager.loadEmotes(); // PlayerAnimator does not support 1.20.2 yet
if (Settings.isEmotesEnabled() && (HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R3") || HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R1"))) EmoteManager.loadEmotes(); // PlayerAnimator does not support 1.20.2 yet
getInstance().getLogger().info("Successfully Enabled HMCCosmetics");
getInstance().getLogger().info(Cosmetics.values().size() + " Cosmetics Successfully Setup");

View File

@@ -0,0 +1,47 @@
package com.hibiscusmc.hmccosmetics.api.events;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
/**
* Called when a cosmetic type not registered with HMCC default cosmetics is attempted to be registered. So if someone puts "test" in the config slot, and it's not a default cosmetic, this event will be called.
*/
public class CosmeticTypeRegisterEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final String id;
private final ConfigurationNode config;
public CosmeticTypeRegisterEvent(String id, ConfigurationNode config) {
this.id = id;
this.config = config;
}
/**
* Returns the id of the cosmetic trying to be registered. For example, "beanie" or "test"
* @return The id. This is the key in the cosmetic config
*/
public String getId() {
return id;
}
/**
* This will already be in the nested node below the id in the config.
* @return The cosmetic config node in the cosmetic config that was attempted to get registered
*/
public ConfigurationNode getConfig() {
return config;
}
@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@@ -427,7 +427,7 @@ public class CosmeticCommand implements CommandExecutor {
CosmeticUser user = CosmeticUsers.getUser(player);
if (!silent) MessagesUtil.sendMessage(sender, "show-cosmetic");
user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.COMMAND);
return true;
}
case ("debug") -> {
@@ -496,6 +496,63 @@ public class CosmeticCommand implements CommandExecutor {
user.getUserEmoteManager().playEmote(args[1]);
return true;
}
case "disableall" -> {
if (!sender.hasPermission("hmccosmetics.cmd.disableall")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (args.length == 1) {
if (!silent) MessagesUtil.sendMessage(player, "not-enough-args");
return true;
}
if (args[1].equalsIgnoreCase("true")) {
Settings.setAllPlayersHidden(true);
for (CosmeticUser user : CosmeticUsers.values()) user.hideCosmetics(CosmeticUser.HiddenReason.DISABLED);
if (!silent) MessagesUtil.sendMessage(sender, "disabled-all");
} else if (args[1].equalsIgnoreCase("false")) {
Settings.setAllPlayersHidden(false);
for (CosmeticUser user : CosmeticUsers.values()) user.showCosmetics(CosmeticUser.HiddenReason.DISABLED);
if (!silent) MessagesUtil.sendMessage(sender, "enabled-all");
} else {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-args");
}
return true;
}
case "hiddenreasons" -> {
if (!sender.hasPermission("hmccosmetics.cmd.hiddenreasons")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (args.length >= 2) {
player = Bukkit.getPlayer(args[1]);
}
if (player == null) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-player");
return true;
}
CosmeticUser user = CosmeticUsers.getUser(player);
sender.sendMessage(user.getHiddenReasons().toString());
return true;
}
case "clearhiddenreasons" -> {
if (!sender.hasPermission("hmccosmetics.cmd.clearhiddenreasons")) {
if (!silent) MessagesUtil.sendMessage(sender, "no-permission");
return true;
}
if (args.length >= 2) {
player = Bukkit.getPlayer(args[1]);
}
if (player == null) {
if (!silent) MessagesUtil.sendMessage(sender, "invalid-player");
return true;
}
CosmeticUser user = CosmeticUsers.getUser(player);
user.clearHiddenReasons();
return true;
}
}
return true;
}

View File

@@ -46,12 +46,16 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (hasPermission(sender, "hmccosmetics.cmd.debug")) completions.add("debug");
if (hasPermission(sender, "hmccosmetics.cmd.emote")) completions.add("emote");
if (hasPermission(sender, "hmccosmetics.cmd.playemote")) completions.add("playemote");
if (hasPermission(sender, "hmccosmetics.cmd.disableall")) completions.add("disableall");
if (hasPermission(sender, "hmccosmetics.cmd.hiddenreasons")) completions.add("hiddenreasons");
if (hasPermission(sender, "hmccosmetics.cmd.clearhiddenreasons")) completions.add("clearhiddenreasons");
StringUtil.copyPartialMatches(args[0], completions, finalCompletions);
}
if (!(sender instanceof Player)) return completions;
CosmeticUser user = CosmeticUsers.getUser(((Player) sender).getUniqueId());
if (user == null) return completions; // User hasn't loaded in yet, can't do proper checks
if (args.length == 2) {
String subcommand = args[0].toLowerCase();
@@ -70,11 +74,15 @@ public class CosmeticCommandTabComplete implements TabCompleter {
if (menu.canOpen(user.getPlayer())) completions.add(menu.getId());
}
}
case "dataclear", "hide", "show", "emote" -> {
case "dataclear", "hide", "show", "emote", "hiddenreasons", "clearhiddenreasons" -> {
for (Player player : Bukkit.getOnlinePlayers()) {
completions.add(player.getName());
}
}
case "disableall" -> {
completions.add("true");
completions.add("false");
}
case "wardrobe" -> {
for (Wardrobe wardrobe : WardrobeSettings.getWardrobes()) {
if (wardrobe.hasPermission()) {

View File

@@ -3,11 +3,13 @@ package com.hibiscusmc.hmccosmetics.config;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
@@ -47,13 +49,13 @@ public class Settings {
private static final String COSMETIC_DISABLED_WORLDS_PATH = "disabled-worlds";
private static final String COSMETIC_PACKET_ENTITY_TELEPORT_COOLDOWN_PATH = "entity-cooldown-teleport-packet";
private static final String COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH = "backpack-force-riding-packet";
private static final String COSMETIC_FORCE_OFFHAND_COSMETIC_SHOW_PATH = "offhand-always-show";
private static final String COSMETIC_ADD_ENCHANTS_HELMET_PATH = "helmet-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_CHESTPLATE_PATH = "chest-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_LEGGINGS_PATH = "leggings-add-enchantments";
private static final String COSMETIC_ADD_ENCHANTS_BOOTS_PATH = "boots-add-enchantments";
private static final String COSMETIC_BACKPACK_LIGHT_EMINATION_PATH = "backpack-light-emination";
private static final String COSMETIC_BACKPACK_LIGHT_BLOCK_DETECTION = "backpack-block-detection";
private static final String COSMETIC_DESTROY_LOOSE_COSMETIC_PATH = "destroy-loose-cosmetics";
private static final String COSMETIC_BALLOON_HEAD_FORWARD_PATH = "balloon-head-forward";
private static final String MENU_SETTINGS_PATH = "menu-settings";
private static final String MENU_CLICK_COOLDOWN_PATH = "click-cooldown";
private static final String MENU_CLICK_COOLDOWN_TIME_PATH = "time";
private static final String COSMETIC_TYPE_SETTINGS_PATH = "cosmetic-type";
private static final String EQUIP_CLICK_TYPE = "equip-click";
private static final String UNEQUIP_CLICK_TYPE = "unequip-click";
@@ -67,6 +69,7 @@ public class Settings {
private static final String EQUIPABLE_COSMETIC_COLOR_PATH = "equipable-cosmetic-color";
private static final String LOCKED_COSMETIC_COLOR_PATH = "locked-cosmetic-color";
private static final String ENABLED_PATH = "enabled";
private static final String SLOT_OPTIONS_PATH = "slot-options";
@Getter
private static String defaultMenu;
@@ -92,14 +95,7 @@ public class Settings {
private static boolean worldGuardMoveCheck;
@Getter
private static boolean cosmeticEmoteBlockCheck;
@Getter
private static boolean addHelmetEnchants;
@Getter
private static boolean addChestplateEnchants;
@Getter
private static boolean addLeggingEnchants;
@Getter
private static boolean addBootsEnchants;
private static final HashMap<EquipmentSlot, SlotOptionConfig> slotOptions = new HashMap<>();
@Getter
private static boolean emoteAirCheck;
@Getter
@@ -111,12 +107,16 @@ public class Settings {
@Getter
private static boolean backpackForceRidingEnabled;
@Getter
private static boolean cosmeticForceOffhandCosmeticShow;
private static boolean backpackLightEmination;
@Getter
private static boolean backpackBlockDetection;
@Getter
private static boolean emotesEnabled;
@Getter
private static boolean disabledGamemodesEnabled;
@Getter
private static boolean balloonHeadForward;
@Getter
private static List<String> disabledGamemodes;
@Getter
private static List<String> disabledWorlds;
@@ -127,6 +127,10 @@ public class Settings {
@Getter
private static int packetEntityTeleportCooldown;
@Getter
private static Long defaultMenuCooldown;
@Getter
private static boolean menuClickCooldown;
@Getter
private static double emoteDistance;
@Getter
private static Vector balloonOffset;
@@ -156,6 +160,8 @@ public class Settings {
private static boolean emoteCameraEnabled;
@Getter
private static boolean emoteMoveCheck;
@Getter @Setter
private static boolean allPlayersHidden;
public static void load(ConfigurationNode source) {
@@ -196,19 +202,33 @@ public class Settings {
emoteInvincible = cosmeticSettings.node(COSMETIC_EMOTE_INVINCIBLE_PATH).getBoolean(false);
destroyLooseCosmetics = cosmeticSettings.node(COSMETIC_DESTROY_LOOSE_COSMETIC_PATH).getBoolean(false);
backpackForceRidingEnabled = cosmeticSettings.node(COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH).getBoolean(false);
addHelmetEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_HELMET_PATH).getBoolean(false);
addChestplateEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_CHESTPLATE_PATH).getBoolean(false);
addLeggingEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_LEGGINGS_PATH).getBoolean(false);
addBootsEnchants = cosmeticSettings.node(COSMETIC_ADD_ENCHANTS_BOOTS_PATH).getBoolean(false);
backpackLightEmination = cosmeticSettings.node(COSMETIC_BACKPACK_LIGHT_EMINATION_PATH).getBoolean(true);
backpackBlockDetection = cosmeticSettings.node(COSMETIC_BACKPACK_LIGHT_BLOCK_DETECTION).getBoolean(true);
cosmeticSettings.node(SLOT_OPTIONS_PATH).childrenMap().forEach((key, value) -> {
EquipmentSlot slot = convertConfigToEquipment(key.toString().toLowerCase());
if (slot == null) {
MessagesUtil.sendDebugMessages("Invalid slot option: " + key, Level.WARNING);
return;
}
boolean addEnchantments = value.node("add-enchantments").getBoolean(false);
boolean requireEmpty = value.node("require-empty").getBoolean(false);
slotOptions.put(slot, new SlotOptionConfig(slot, addEnchantments, requireEmpty));
});
tickPeriod = cosmeticSettings.node(TICK_PERIOD_PATH).getInt(-1);
viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt(-3);
emoteCameraEnabled = cosmeticSettings.node(COSMETIC_EMOTE_CAMERA_PATH).getBoolean(true);
emoteMoveCheck = cosmeticSettings.node(COSMETIC_EMOTE_MOVE_CHECK_PATH).getBoolean(false);
packetEntityTeleportCooldown = cosmeticSettings.node(COSMETIC_PACKET_ENTITY_TELEPORT_COOLDOWN_PATH).getInt(-1);
cosmeticForceOffhandCosmeticShow = cosmeticSettings.node(COSMETIC_FORCE_OFFHAND_COSMETIC_SHOW_PATH).getBoolean(false);
balloonHeadForward = cosmeticSettings.node(COSMETIC_BALLOON_HEAD_FORWARD_PATH).getBoolean(false);
ConfigurationNode menuSettings = source.node(MENU_SETTINGS_PATH);
ConfigurationNode clickCooldownSettings = menuSettings.node(MENU_CLICK_COOLDOWN_PATH);
menuClickCooldown = clickCooldownSettings.node(ENABLED_PATH).getBoolean(true);
defaultMenuCooldown = clickCooldownSettings.node(MENU_CLICK_COOLDOWN_TIME_PATH).getLong(1000L);
ConfigurationNode shadingSettings = menuSettings.node(SHADING_PATH);
defaultShading = shadingSettings.node(ENABLED_PATH).getBoolean();
firstRowShift = shadingSettings.node(FIRST_ROW_SHIFT_PATH).getString();
@@ -250,24 +270,9 @@ public class Settings {
return new Vector(config.node("x").getDouble(), config.node("y").getDouble(), config.node("z").getDouble());
}
public static boolean getShouldAddEnchants(EquipmentSlot slot) {
switch (slot) {
case HEAD -> {
return addHelmetEnchants;
}
case CHEST -> {
return addChestplateEnchants;
}
case LEGS -> {
return addLeggingEnchants;
}
case FEET -> {
return addBootsEnchants;
}
default -> {
return false;
}
}
public static SlotOptionConfig getSlotOption(EquipmentSlot slot) {
if (!slotOptions.containsKey(slot)) slotOptions.put(slot, new SlotOptionConfig(slot, false, false));
return slotOptions.get(slot);
}
public static void setDebugMode(boolean newSetting) {
@@ -279,4 +284,16 @@ public class Settings {
plugin.saveConfig();
}
private static EquipmentSlot convertConfigToEquipment(String slot) {
return switch (slot) {
case "helmet" -> EquipmentSlot.HEAD;
case "chestplate" -> EquipmentSlot.CHEST;
case "leggings" -> EquipmentSlot.LEGS;
case "boots" -> EquipmentSlot.FEET;
case "offhand" -> EquipmentSlot.OFF_HAND;
case "mainhand" -> EquipmentSlot.HAND;
default -> null;
};
}
}

View File

@@ -0,0 +1,20 @@
package com.hibiscusmc.hmccosmetics.config;
import lombok.Getter;
import org.bukkit.inventory.EquipmentSlot;
public class SlotOptionConfig {
@Getter
private final EquipmentSlot slot;
@Getter
private final boolean addEnchantments;
@Getter
private final boolean requireEmpty;
public SlotOptionConfig(EquipmentSlot slot, boolean addEnchantments, boolean requireEmpty) {
this.slot = slot;
this.addEnchantments = addEnchantments;
this.requireEmpty = requireEmpty;
}
}

View File

@@ -33,6 +33,8 @@ public class WardrobeSettings {
private static final String EQUIP_PUMPKIN_WARDROBE = "equip-pumpkin";
private static final String TRY_COSMETICS_WARDROBE = "unchecked-wardrobe-cosmetics";
private static final String RETURN_LAST_LOCATION = "return-last-location";
private static final String DAMAGE_KICK_PATH = "damage-kicked";
private static final String PREVENT_DAMAGE_PATH = "prevent-damage";
private static final String WARDROBE_MENU_OPTIONS = "menu-options";
private static final String WARDROBE_ENTER_OPEN_MENU_PATH = "enter-open-menu";
@@ -87,6 +89,10 @@ public class WardrobeSettings {
@Getter
private static boolean forceExitGamemode;
@Getter
private static boolean damagedKicked;
@Getter
private static boolean preventDamage;
@Getter
private static GameMode exitGamemode;
private static HashMap<String, Wardrobe> wardrobes;
@Getter
@@ -121,6 +127,8 @@ public class WardrobeSettings {
equipPumpkin = source.node(EQUIP_PUMPKIN_WARDROBE).getBoolean();
returnLastLocation = source.node(RETURN_LAST_LOCATION).getBoolean(false);
tryCosmeticsInWardrobe = source.node(TRY_COSMETICS_WARDROBE).getBoolean(false);
damagedKicked = source.node(DAMAGE_KICK_PATH).getBoolean(false);
preventDamage = source.node(PREVENT_DAMAGE_PATH).getBoolean(true);
ConfigurationNode menuOptionsNode = source.node(WARDROBE_MENU_OPTIONS);
enterOpenMenu = menuOptionsNode.node(WARDROBE_ENTER_OPEN_MENU_PATH).getBoolean(false);

View File

@@ -2,16 +2,23 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.ItemDisplayMetadata;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.Material;
import org.bukkit.entity.Display;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
public abstract class Cosmetic {
@@ -76,4 +83,52 @@ public abstract class Cosmetic {
throw new RuntimeException(e);
}
}
protected ItemDisplayMetadata generateItemDisplayMetadata(ConfigurationNode config) {
ItemDisplayMetadata metadata = new ItemDisplayMetadata();
if (!config.virtual()) {
ConfigurationNode translationNode = config.node("translation");
ConfigurationNode scaleNode = config.node("scale");
ConfigurationNode rotationLeftNode = config.node("rotation-left");
ConfigurationNode rotationRightNode = config.node("rotation-right");
ConfigurationNode skyLightNode = config.node("sky-light");
ConfigurationNode viewRangeNode = config.node("viewrange");
ConfigurationNode widthNode = config.node("width");
ConfigurationNode heightNode = config.node("height");
ConfigurationNode displayTransformNode = config.node("display-transform");
ConfigurationNode itemstackNode = config.node("item");
if (!translationNode.virtual()) metadata.translation = stringToVector(translationNode.getString("0,0,0"));
if (!scaleNode.virtual()) metadata.scale = stringToVector(scaleNode.getString("1,1,1"));
if (!rotationLeftNode.virtual()) metadata.rotationLeft = stringToQuaternion(rotationLeftNode.getString("0,0,0,1"));
if (!rotationRightNode.virtual()) metadata.rotationRight = stringToQuaternion(rotationRightNode.getString("0,0,0,1"));
if (!skyLightNode.virtual()) metadata.skyLight = skyLightNode.getInt(15);
if (!viewRangeNode.virtual()) metadata.viewRange = viewRangeNode.getFloat(1);
if (!widthNode.virtual()) metadata.width = widthNode.getFloat(0);
if (!heightNode.virtual()) metadata.height = heightNode.getFloat(0);
if (!displayTransformNode.virtual()) try {
metadata.displayTransform = ItemDisplay.ItemDisplayTransform.valueOf(displayTransformNode.getString());
} catch (Exception ignored) {}
if (!itemstackNode.virtual()) try {
metadata.itemStack = ItemSerializer.INSTANCE.deserialize(ItemStack.class, itemstackNode);
} catch (Exception ignored) {}
}
return metadata;
}
protected Vector3f stringToVector(String string) {
List<String> vector = Arrays.stream(string.replace(" ", "").split(",", 3)).toList();
while (vector.size() < 3) vector.add("0");
float x = Float.parseFloat(vector.get(0)), y = Float.parseFloat(vector.get(1)), z = Float.parseFloat(vector.get(2));
return new Vector3f(x, y, z);
}
protected Quaternionf stringToQuaternion(String string) {
List<String> vector = Arrays.stream(string.replace(" ", "").split(",", 4)).toList();
while (vector.size() < 3) vector.add("0");
if (vector.size() < 4) vector.add("1");
float x = Float.parseFloat(vector.get(0)), y = Float.parseFloat(vector.get(1)), z = Float.parseFloat(vector.get(2)), w = Float.parseFloat(vector.get(3));
return new Quaternionf(x, y, z, w);
}
}

View File

@@ -9,5 +9,6 @@ public enum CosmeticSlot {
OFFHAND,
BACKPACK,
BALLOON,
EMOTE
EMOTE,
CUSTOM
}

View File

@@ -2,6 +2,7 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.google.common.collect.HashBiMap;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.CosmeticTypeRegisterEvent;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.types.*;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -105,12 +106,13 @@ public class Cosmetics {
MessagesUtil.sendDebugMessages("Unable to create " + id + " because " + slotNode.getString() + " is not a valid slot!", Level.WARNING);
continue;
}
switch (CosmeticSlot.valueOf(cosmeticConfig.node("slot").getString())) {
switch (CosmeticSlot.valueOf(slotNode.getString())) {
case BALLOON -> new CosmeticBalloonType(id, cosmeticConfig);
case BACKPACK -> new CosmeticBackpackType(id, cosmeticConfig);
case MAINHAND -> new CosmeticMainhandType(id, cosmeticConfig);
case EMOTE -> new CosmeticEmoteType(id, cosmeticConfig);
default -> new CosmeticArmorType(id, cosmeticConfig);
case HELMET, CHESTPLATE, LEGGINGS, BOOTS, OFFHAND -> new CosmeticArmorType(id, cosmeticConfig);
default -> new CosmeticTypeRegisterEvent(id, cosmeticConfig).callEvent();
}
} catch (Exception e) {
if (Settings.isDebugMode()) e.printStackTrace();

View File

@@ -30,9 +30,9 @@ public class CosmeticArmorType extends Cosmetic {
if (user.getUserEmoteManager().isPlayingEmote() || user.isInWardrobe()) return;
Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return;
if (!Settings.isCosmeticForceOffhandCosmeticShow()
&& equipSlot.equals(EquipmentSlot.OFF_HAND)
&& ((user.getEntity() instanceof Player) && !user.getPlayer().getInventory().getItemInOffHand().getType().isAir())) return;
if (Settings.getSlotOption(equipSlot).isRequireEmpty() && entity instanceof HumanEntity humanEntity) {
if (!humanEntity.getInventory().getItem(equipSlot).getType().isAir()) return;
}
ItemStack item = getItem(user);
if (item == null) return;
PacketManager.equipmentSlotUpdate(entity.getEntityId(), equipSlot, item, HMCCPacketManager.getViewers(entity.getLocation()));
@@ -44,7 +44,7 @@ public class CosmeticArmorType extends Cosmetic {
public ItemStack getItem(@NotNull CosmeticUser user, ItemStack cosmeticItem) {
if (!(user.getEntity() instanceof HumanEntity humanEntity)) return null;
if (Settings.getShouldAddEnchants(equipSlot)) {
if (Settings.getSlotOption(equipSlot).isAddEnchantments()) {
ItemStack equippedItem = humanEntity.getInventory().getItem(equipSlot);
cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments());
}

View File

@@ -3,17 +3,18 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.ItemDisplayMetadata;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import lombok.Setter;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -29,16 +30,24 @@ public class CosmeticBackpackType extends Cosmetic {
@Getter
private int height = -1;
private ItemStack firstPersonBackpack;
@Getter @Setter
private ItemDisplayMetadata metadata;
@Getter @Setter
private ItemDisplayMetadata firstPersonMetadata;
public CosmeticBackpackType(String id, ConfigurationNode config) {
super(id, config);
modelName = config.node("model").getString();
if (!config.node("firstperson-item").virtual()) {
this.firstPersonBackpack = generateItemStack(config.node("firstperson-item"));
ConfigurationNode firstPersonNode = config.node("firstperson-item");
if (!firstPersonNode.virtual()) {
this.firstPersonBackpack = generateItemStack(firstPersonNode);
this.height = config.node("height").getInt(5);
}
this.firstPersonMetadata = generateItemDisplayMetadata(config.node("firstperson-metadata")).setVertical();
this.metadata = generateItemDisplayMetadata(config.node("metadata")).setFixed();
}
@Override
@@ -46,26 +55,30 @@ public class CosmeticBackpackType extends Cosmetic {
Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return;
Location loc = entity.getLocation().clone().add(0, 2, 0);
Location loc = entity.getLocation();
if (user.isInWardrobe() || !user.isBackpackSpawned()) return;
// This needs to be moved to purely packet based, there are far to many plugin doing dumb stuff that prevents spawning armorstands ignoring our spawn reason.
if (user.isHidden()) {
// Sometimes the backpack is not despawned when the player is hidden (weird ass logic happening somewhere)
user.despawnBackpack();
return;
}
List<Player> outsideViewers = user.getUserBackpackManager().getEntityManager().refreshViewers(loc);
user.getUserBackpackManager().getEntityManager().teleport(loc);
user.getUserBackpackManager().getEntityManager().setRotation((int) loc.getYaw(), isFirstPersonCompadible());
UserBackpackManager backpackManager = user.getUserBackpackManager();
//backpackManager.getEntityManager().setRotation((int) loc.getYaw(), false);
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), user.getUserBackpackManager().getFirstArmorStandId(), EntityType.ARMOR_STAND, UUID.randomUUID(), outsideViewers);
HMCCPacketManager.sendArmorstandMetadata(user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), outsideViewers);
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), backpackManager.getFirstItemDisplayId(), EntityType.ITEM_DISPLAY, UUID.randomUUID(), outsideViewers);
//metadata.rotationLeft.rotateY((float) Math.toRadians(loc.getYaw()));
HMCCPacketManager.sendItemDisplayMetadata(backpackManager.getFirstItemDisplayId(), metadata, user.getUserCosmeticItem(this, getItem()), outsideViewers);
// If true, it will send the riding packet to all players. If false, it will send the riding packet only to new players
if (Settings.isBackpackForceRidingEnabled()) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), user.getUserBackpackManager().getEntityManager().getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
if (Settings.isBackpackForceRidingEnabled()) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), backpackManager.getFirstItemDisplayId(), backpackManager.getEntityManager().getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), user.getUserBackpackManager().getFirstItemDisplayId(), outsideViewers);
if (!user.isInWardrobe() && isFirstPersonCompadible() && user.getPlayer() != null) {
if (!user.isInWardrobe() && isFirstPersonCompatible() && user.getPlayer() != null) {
List<Player> owner = List.of(user.getPlayer());
ArrayList<Integer> particleCloud = user.getUserBackpackManager().getAreaEffectEntityId();
ArrayList<Integer> particleCloud = backpackManager.getAreaEffectEntityId();
for (int i = 0; i < particleCloud.size(); i++) {
if (i == 0) {
HMCCPacketManager.sendRidingPacket(entity.getEntityId(), particleCloud.get(i), owner);
@@ -73,19 +86,18 @@ public class CosmeticBackpackType extends Cosmetic {
HMCCPacketManager.sendRidingPacket(particleCloud.get(i - 1), particleCloud.get(i) , owner);
}
}
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), user.getUserBackpackManager().getFirstArmorStandId(), owner);
if (!user.getHidden()) {
//if (loc.getPitch() < -70) NMSHandlers.getHandler().equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, new ItemStack(Material.AIR), owner);
//else NMSHandlers.getHandler().equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, firstPersonBackpack, owner);
PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), backpackManager.getFirstItemDisplayId(), owner);
if (!user.isHidden()) {
HMCCPacketManager.sendItemDisplayMetadata(backpackManager.getFirstItemDisplayId(), firstPersonMetadata, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
}
MessagesUtil.sendDebugMessages("First Person Backpack Update[owner=" + user.getUniqueId() + ",player_location=" + loc + "]!", Level.INFO);
}
user.getUserBackpackManager().showBackpack();
//MessagesUtil.sendDebugMessages("TTTTTTT " + backpackManager.refreshBlock(backpackManager.getEntityManager().getViewers()));
backpackManager.showBackpack();
}
public boolean isFirstPersonCompadible() {
public boolean isFirstPersonCompatible() {
return firstPersonBackpack != null;
}

View File

@@ -68,6 +68,7 @@ public class CosmeticBalloonType extends Cosmetic {
Location newLocation = entity.getLocation();
Location currentLocation = user.getBalloonManager().getLocation();
newLocation = newLocation.clone().add(getBalloonOffset());
if (Settings.isBalloonHeadForward()) newLocation.setPitch(0);
List<Player> viewer = HMCCPacketManager.getViewers(entity.getLocation());
@@ -83,11 +84,11 @@ public class CosmeticBalloonType extends Cosmetic {
HMCCPacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
HMCCPacketManager.sendLeashPacket(userBalloonManager.getPufferfishBalloonId(), entity.getEntityId(), viewer);
if (user.getHidden()) {
if (user.isHidden()) {
userBalloonManager.getPufferfish().hidePufferfish();
return;
}
if (!user.getHidden() && showLead) {
if (!user.isHidden() && showLead) {
List<Player> sendTo = userBalloonManager.getPufferfish().refreshViewers(newLocation);
if (sendTo.isEmpty()) return;
user.getBalloonManager().getPufferfish().spawnPufferfish(newLocation, sendTo);

View File

@@ -3,6 +3,7 @@ package com.hibiscusmc.hmccosmetics.database;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.database.types.Data;
import com.hibiscusmc.hmccosmetics.database.types.MySQLData;
import com.hibiscusmc.hmccosmetics.database.types.NoneData;
import com.hibiscusmc.hmccosmetics.database.types.SQLiteData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
@@ -11,6 +12,7 @@ import lombok.Getter;
import org.bukkit.entity.Player;
import java.util.UUID;
import java.util.logging.Level;
public class Database {
@@ -18,18 +20,25 @@ public class Database {
private static Data data;
private static final MySQLData MYSQL_DATA = new MySQLData();
private static final SQLiteData SQLITE_DATA = new SQLiteData();
private static final NoneData NONE_DATA = new NoneData();
public Database() {
String databaseType = DatabaseSettings.getDatabaseType();
data = SQLITE_DATA; // default
if (databaseType.equalsIgnoreCase("MySQL")) {
data = SQLITE_DATA; // default to SQLite, then check if it's anything different
switch (databaseType.toLowerCase()) {
case "mysql":
data = MYSQL_DATA;
break;
case "sqlite":
// already the default
break;
case "none":
data = NONE_DATA;
MessagesUtil.sendDebugMessages("Database is set to none. Data will not be saved.", Level.WARNING);
break;
default:
MessagesUtil.sendDebugMessages("Invalid database type. Defaulting to SQLite.", Level.WARNING);
}
/* SQLite is the default database. Might change in the future, so keep code here in case.
if (databaseType.equalsIgnoreCase("sqlite")) {
data = SQLITE_DATA;
}
*/
MessagesUtil.sendDebugMessages("Database is " + data);
setup();

View File

@@ -13,9 +13,7 @@ import org.bukkit.Color;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.*;
public abstract class Data {
@@ -32,9 +30,9 @@ public abstract class Data {
@NotNull
public final String serializeData(@NotNull CosmeticUser user) {
StringBuilder data = new StringBuilder();
if (user.getHidden()) {
if (shouldHiddenSave(user.getHiddenReason())) {
data.append("HIDDEN=").append(user.getHiddenReason());
if (user.isHidden()) {
for (CosmeticUser.HiddenReason reason : user.getHiddenReasons()) {
if (shouldHiddenSave(reason)) data.append("HIDDEN=").append(reason);
}
}
for (Cosmetic cosmetic : user.getCosmetics()) {
@@ -59,6 +57,7 @@ public abstract class Data {
Map<CosmeticSlot, Map<Cosmetic, Color>> cosmetics = new HashMap<>();
String[] rawData = raw.split(",");
ArrayList<CosmeticUser.HiddenReason> hiddenReason = new ArrayList<>();
for (String a : rawData) {
if (a == null || a.isEmpty()) continue;
String[] splitData = a.split("=");
@@ -68,9 +67,7 @@ public abstract class Data {
if (splitData[0].equalsIgnoreCase("HIDDEN")) {
if (EnumUtils.isValidEnum(CosmeticUser.HiddenReason.class, splitData[1])) {
if (Settings.isForceShowOnJoin()) continue;
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
user.hideCosmetics(CosmeticUser.HiddenReason.valueOf(splitData[1]));
});
hiddenReason.add(CosmeticUser.HiddenReason.valueOf(splitData[1]));
}
continue;
}
@@ -98,12 +95,46 @@ public abstract class Data {
cosmetics.put(slot, cosmeticColorHashMap);
}
}
MessagesUtil.sendDebugMessages("Hidden Reason: " + hiddenReason);
// if else this, if else that, if else I got to deal with this anymore i'll lose my mind
if (!hiddenReason.isEmpty()) {
for (CosmeticUser.HiddenReason reason : hiddenReason) user.silentlyAddHideFlag(reason);
} else {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// Handle gamemode check
if (user.getPlayer() != null && Settings.isDisabledGamemodesEnabled() && Settings.getDisabledGamemodes().contains(user.getPlayer().getGameMode().toString())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to gamemode");
user.hideCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
return;
} else {
if (user.isHidden(CosmeticUser.HiddenReason.GAMEMODE)) {
MessagesUtil.sendDebugMessages("Join Gamemode Check: Showing Cosmetics");
user.showCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
return;
}
}
// Handle world check
if (user.getPlayer() != null && Settings.getDisabledWorlds().contains(user.getPlayer().getWorld().getName())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to world");
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else {
if (user.isHidden(CosmeticUser.HiddenReason.WORLD)) {
MessagesUtil.sendDebugMessages("Join World Check: Showing Cosmetics");
user.showCosmetics(CosmeticUser.HiddenReason.WORLD);
}
}
if (Settings.isAllPlayersHidden()) {
user.hideCosmetics(CosmeticUser.HiddenReason.DISABLED);
}
});
}
return cosmetics;
}
private boolean shouldHiddenSave(CosmeticUser.HiddenReason reason) {
switch (reason) {
case EMOTE, NONE, GAMEMODE, WORLD -> {
case EMOTE, NONE, GAMEMODE, WORLD, DISABLED -> {
return false;
}
default -> {

View File

@@ -13,6 +13,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
public class MySQLData extends SQLData {
@@ -59,12 +60,17 @@ public class MySQLData extends SQLData {
@Override
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedSt = null;
try {
PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
});
}
@@ -127,7 +133,14 @@ public class MySQLData extends SQLData {
public PreparedStatement preparedStatement(String query) {
PreparedStatement ps = null;
if (!isConnectionOpen()) MessagesUtil.sendDebugMessages("Connection is not open");
if (!isConnectionOpen()) {
MessagesUtil.sendDebugMessages("The MySQL database connection is not open (Could the database been idle for to long?). Reconnecting...", Level.WARNING);
try {
openConnection();
} catch (SQLException e) {
e.printStackTrace();
}
}
try {
if (connection == null) throw new NullPointerException("Connection is null");

View File

@@ -0,0 +1,28 @@
package com.hibiscusmc.hmccosmetics.database.types;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class NoneData extends Data {
@Override
public void setup() {
// Nothing
}
@Override
public void save(CosmeticUser user) {
// Nothing
}
@Override
public @Nullable CosmeticUser get(UUID uniqueId) {
return new CosmeticUser(uniqueId);
}
@Override
public void clear(UUID uniqueId) {
// Nothing
}
}

View File

@@ -10,6 +10,7 @@ import org.bukkit.Color;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -20,24 +21,35 @@ public abstract class SQLData extends Data {
CosmeticUser user = new CosmeticUser(uniqueId);
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedStatement = null;
try {
PreparedStatement preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;");
preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;");
preparedStatement.setString(1, uniqueId.toString());
ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) {
String rawData = rs.getString("COSMETICS");
Map<CosmeticSlot, Map<Cosmetic, Color>> cosmetics = deserializeData(user, rawData);
// Load cosmetics, put them into the addedCosmetic hashmap
HashMap<Cosmetic, Color> addedCosmetics = new HashMap<>();
for (Map<Cosmetic, Color> cosmeticColors : cosmetics.values()) {
for (Cosmetic cosmetic : cosmeticColors.keySet()) {
addedCosmetics.put(cosmetic, cosmeticColors.get(cosmetic));
}
}
// Run a task on the main thread, adding the cosmetics to the player
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
// This can not be async.
user.addPlayerCosmetic(cosmetic, cosmeticColors.get(cosmetic));
for (Cosmetic cosmetic : addedCosmetics.keySet()) {
user.addPlayerCosmetic(cosmetic, addedCosmetics.get(cosmetic));
}
});
}
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null) preparedStatement.close();
} catch (SQLException e) {}
}
});
@@ -48,13 +60,18 @@ public abstract class SQLData extends Data {
@SuppressWarnings("resource")
public void save(CosmeticUser user) {
Runnable run = () -> {
PreparedStatement preparedSt = null;
try {
PreparedStatement preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);");
preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);");
preparedSt.setString(1, user.getUniqueId().toString());
preparedSt.setString(2, serializeData(user));
preparedSt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
};
if (!HMCCosmeticsPlugin.getInstance().isDisabled()) {

View File

@@ -48,12 +48,17 @@ public class SQLiteData extends SQLData {
@SuppressWarnings("resource")
public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
PreparedStatement preparedSt = null;
try {
PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
}
});
}

View File

@@ -40,6 +40,8 @@ public class Menu {
@Getter
private final int rows;
@Getter
private final Long cooldown;
@Getter
private final ConfigurationNode config;
@Getter
private final String permissionNode;
@@ -55,6 +57,7 @@ public class Menu {
title = config.node("title").getString("chest");
rows = config.node("rows").getInt(1);
cooldown = config.node("click-cooldown").getLong(Settings.getDefaultMenuCooldown());
permissionNode = config.node("permission").getString("");
refreshRate = config.node("refresh-rate").getInt(-1);
shading = config.node("shading").getBoolean(Settings.isDefaultShading());
@@ -90,7 +93,8 @@ public class Menu {
try {
item = ItemSerializer.INSTANCE.deserialize(ItemStack.class, config.node("item"));
} catch (SerializationException e) {
throw new RuntimeException(e);
MessagesUtil.sendDebugMessages("Unable to get valid item for " + config.key().toString() + " " + e.getMessage());
continue;
}
if (item == null) {
@@ -244,13 +248,24 @@ public class Menu {
if (modifiedItem.getType().isAir()) continue;
GuiItem guiItem = ItemBuilder.from(modifiedItem).asGuiItem();
guiItem.setAction(event -> {
MessagesUtil.sendDebugMessages("Selected slot " + slot);
UUID uuid = user.getUniqueId();
if (Settings.isMenuClickCooldown()) {
Long userCooldown = Menus.getCooldown(uuid);
if (userCooldown != 0 && (System.currentTimeMillis() - Menus.getCooldown(uuid) <= getCooldown())) {
MessagesUtil.sendDebugMessages("Cooldown for " + user.getUniqueId() + " System time: " + System.currentTimeMillis() + " Cooldown: " + Menus.getCooldown(user.getUniqueId()) + " Difference: " + (System.currentTimeMillis() - Menus.getCooldown(user.getUniqueId())));
MessagesUtil.sendMessage(user.getPlayer(), "on-click-cooldown");
return;
} else {
Menus.addCooldown(user.getUniqueId(), System.currentTimeMillis());
}
}
MessagesUtil.sendDebugMessages("Updated Menu Item in slot number " + slot);
final ClickType clickType = event.getClick();
if (type != null) type.run(user, item.itemConfig(), clickType);
updateMenu(user, gui);
});
MessagesUtil.sendDebugMessages("Added " + slot + " as " + guiItem + " in the menu");
MessagesUtil.sendDebugMessages("Set an item in slot " + slot + " in the menu of " + getId());
gui.updateItem(slot, guiItem);
break;
}

View File

@@ -13,16 +13,14 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Stream;
public class Menus {
private static final HashMap<String, Menu> MENUS = new HashMap<>();
private static final HashMap<UUID, Long> COOLDOWNS = new HashMap<>();
public static void addMenu(Menu menu) {
MENUS.put(menu.getId().toUpperCase(), menu);
@@ -63,8 +61,21 @@ public class Menus {
return MENUS.values();
}
public static void addCooldown(UUID uuid, long time) {
COOLDOWNS.put(uuid, time);
}
public static Long getCooldown(UUID uuid) {
return COOLDOWNS.getOrDefault(uuid, 0L);
}
public static void removeCooldown(UUID uuid) {
COOLDOWNS.remove(uuid);
}
public static void setup() {
MENUS.clear();
COOLDOWNS.clear();
File cosmeticFolder = new File(HMCCosmeticsPlugin.getInstance().getDataFolder() + "/menus");
if (!cosmeticFolder.exists()) cosmeticFolder.mkdir();

View File

@@ -3,7 +3,7 @@ package com.hibiscusmc.hmccosmetics.gui.action;
import com.hibiscusmc.hmccosmetics.gui.action.actions.*;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;

View File

@@ -12,7 +12,7 @@ public class ActionCosmeticHide extends Action {
@Override
public void run(@NotNull CosmeticUser user, String raw) {
if (user.getHidden()) return;
if (user.isHidden()) return;
user.hideCosmetics(CosmeticUser.HiddenReason.ACTION);
}
}

View File

@@ -12,10 +12,10 @@ public class ActionCosmeticShow extends Action {
@Override
public void run(@NotNull CosmeticUser user, String raw) {
if (!user.getHidden()) return;
if (!user.isHidden()) return;
// Do not hide if it's already off for WG
if (user.getHiddenReason() != CosmeticUser.HiddenReason.ACTION && user.getHiddenReason() != CosmeticUser.HiddenReason.COMMAND) return;
user.showCosmetics();
if (!user.isHidden(CosmeticUser.HiddenReason.ACTION) && !user.isHidden(CosmeticUser.HiddenReason.COMMAND)) return;
user.showCosmetics(CosmeticUser.HiddenReason.ACTION);
}
}

View File

@@ -12,9 +12,9 @@ public class ActionCosmeticToggle extends Action {
@Override
public void run(@NotNull CosmeticUser user, String raw) {
if (user.getHidden()) {
if (user.getHiddenReason() != CosmeticUser.HiddenReason.ACTION && user.getHiddenReason() != CosmeticUser.HiddenReason.COMMAND) return;
user.showCosmetics();
if (user.isHidden()) {
if (!user.isHidden(CosmeticUser.HiddenReason.ACTION) && !user.isHidden(CosmeticUser.HiddenReason.COMMAND)) return;
user.showCosmetics(CosmeticUser.HiddenReason.ACTION);
return;
}

View File

@@ -8,17 +8,16 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import me.lojosho.hibiscuscommons.util.ColorBuilder;
import me.lojosho.hibiscuscommons.util.StringUtils;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.inventory.meta.*;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class DyeMenu {
public static void openMenu(@NotNull CosmeticUser user, Cosmetic cosmetic) {
@@ -32,7 +31,7 @@ public class DyeMenu {
if (originalItem == null || !cosmetic.isDyable()) return;
Gui gui = HMCColorApi.createColorMenu(player);
gui.updateTitle(Hooks.processPlaceholders(player, Settings.getDyeMenuName()));
gui.updateTitle(Hooks.processPlaceholders(player, StringUtils.parseStringToString(Settings.getDyeMenuName())));
gui.setItem(Settings.getDyeMenuInputSlot(), new GuiItem(originalItem));
gui.setDefaultTopClickAction(event -> {
if (event.getSlot() == Settings.getDyeMenuOutputSlot()) {
@@ -41,9 +40,19 @@ public class DyeMenu {
ItemMeta meta = item.getItemMeta();
if (meta == null) return;
Color color = meta instanceof LeatherArmorMeta leatherMeta ? leatherMeta.getColor() :
meta instanceof PotionMeta potionMeta ? potionMeta.getColor() :
meta instanceof MapMeta mapMeta ? mapMeta.getColor() : null;
Color color = null;
if (meta instanceof LeatherArmorMeta leatherMeta) {
color = leatherMeta.getColor();
} else if (meta instanceof PotionMeta potionMeta) {
color = potionMeta.getColor();
} else if (meta instanceof MapMeta mapMeta) {
color = mapMeta.getColor();
} else if (meta instanceof FireworkEffectMeta fireworkEffectMeta) {
FireworkEffect effect = fireworkEffectMeta.getEffect();
if (effect != null) {
color = effect.getColors().stream().findFirst().isPresent() ? effect.getColors().stream().findFirst().get() : null;
}
}
if (color == null) return;
addCosmetic(user, cosmetic, color);

View File

@@ -140,9 +140,9 @@ public class TypeCosmetic extends Type {
return itemStack;
}
if (user.hasCosmeticInSlot(cosmetic) && !config.node("equipped-item").virtual()) {
if (user.hasCosmeticInSlot(cosmetic) && (!config.node("equipped-item").virtual() || !config.node("locked-equipped-item").virtual())) {
MessagesUtil.sendDebugMessages("GUI Equipped Item");
ConfigurationNode equippedItem = config.node("equipped-item");
ConfigurationNode equippedItem = config.node(user.canEquipCosmetic(cosmetic, true) && !config.node("equipped-item").virtual() ? "equipped-item" : "locked-equipped-item");
try {
if (equippedItem.node("material").virtual()) equippedItem.node("material").set(config.node("item", "material").getString());
} catch (SerializationException e) {

View File

@@ -167,6 +167,8 @@ public class HMCPlaceholderExpansion extends PlaceholderExpansion {
} else {
return TranslationUtil.getTranslation("amount-cosmetic", String.valueOf(Cosmetics.values().size()));
}
case "hidden":
return TranslationUtil.getTranslation("hidden", String.valueOf(user.isHidden()));
case "wardrobe-enabled":
return TranslationUtil.getTranslation("in-wardrobe", String.valueOf(user.isInWardrobe()));
}

View File

@@ -30,15 +30,15 @@ public class WGListener implements Listener {
if (user == null) return;
Location location = event.getPlayer().getLocation();
ApplicableRegionSet set = getRegions(location);
if (user.getHidden()) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD && set.getRegions().isEmpty()) {
user.showCosmetics();
if (user.isHidden()) {
if (set.getRegions().isEmpty()) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
}
for (ProtectedRegion protectedRegion : set.getRegions()) {
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticEnableFlag())) {
if (protectedRegion.getFlags().get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD) user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
return;
}
user.hideCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
@@ -58,15 +58,15 @@ public class WGListener implements Listener {
if (user == null) return;
Location location = event.getTo();
ApplicableRegionSet set = getRegions(location);
if (user.getHidden()) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD && set.getRegions().isEmpty()) {
user.showCosmetics();
if (user.isHidden()) {
if (set.getRegions().isEmpty()) {
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
}
}
for (ProtectedRegion protectedRegion : set.getRegions()) {
if (protectedRegion.getFlags().containsKey(WGHook.getCosmeticEnableFlag())) {
if (protectedRegion.getFlags().get(WGHook.getCosmeticEnableFlag()).toString().equalsIgnoreCase("ALLOW")) {
if (user.getHiddenReason() == CosmeticUser.HiddenReason.WORLDGUARD) user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);
return;
}
user.hideCosmetics(CosmeticUser.HiddenReason.WORLDGUARD);

View File

@@ -1,6 +1,7 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
@@ -17,6 +18,14 @@ public class PaperPlayerGameListener implements Listener {
user.updateCosmetic(slotTypeToCosmeticType(event.getSlotType()));
}
@EventHandler
public void onPlayerRespawn(PlayerPostRespawnEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
if (user.isInWardrobe()) return;
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) user.respawnBackpack();
}
private CosmeticSlot slotTypeToCosmeticType(PlayerArmorChangeEvent.SlotType slotType) {
return switch (slotType) {
case HEAD -> CosmeticSlot.HELMET;

View File

@@ -4,6 +4,7 @@ import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.DatabaseSettings;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
@@ -38,22 +39,6 @@ public class PlayerConnectionListener implements Listener {
CosmeticUsers.addUser(user);
MessagesUtil.sendDebugMessages("Run User Join");
// Handle gamemode check
if (Settings.getDisabledGamemodes().contains(user.getPlayer().getGameMode().toString())) {
user.hideCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
} else {
if (user.getHiddenReason() != null && user.getHiddenReason().equals(CosmeticUser.HiddenReason.GAMEMODE)) {
user.showCosmetics();
}
}
// Handle world check
if (Settings.getDisabledWorlds().contains(user.getPlayer().getWorld().getName())) {
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else {
if (user.getHiddenReason() != null && user.getHiddenReason().equals(CosmeticUser.HiddenReason.WORLD)) {
user.showCosmetics();
}
}
// And finally, launch an update for the cosmetics they have.
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (user.getPlayer() == null) return;
@@ -81,6 +66,7 @@ public class PlayerConnectionListener implements Listener {
user.getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.CONNECTION);
event.getPlayer().setInvisible(false);
}
Menus.removeCooldown(event.getPlayer().getUniqueId()); // Removes any menu cooldowns a player might have
Database.save(user);
user.destroy();
CosmeticUsers.removeUser(user.getUniqueId());

View File

@@ -11,6 +11,7 @@ import com.comphenix.protocol.wrappers.Pair;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.PlayerCosmeticPostEquipEvent;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
@@ -26,9 +27,7 @@ import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import me.lojosho.hibiscuscommons.api.events.HibiscusHookReload;
import me.lojosho.hibiscuscommons.api.events.HibiscusPlayerUnVanishEvent;
import me.lojosho.hibiscuscommons.api.events.HibiscusPlayerVanishEvent;
import me.lojosho.hibiscuscommons.api.events.*;
import me.lojosho.hibiscuscommons.hooks.items.HookItemAdder;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit;
@@ -115,7 +114,7 @@ public class PlayerGameListener implements Listener {
user.leaveWardrobe();
}
@EventHandler(priority = EventPriority.LOW)
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer().getUniqueId());
@@ -134,9 +133,7 @@ public class PlayerGameListener implements Listener {
if (Settings.getDisabledWorlds().contains(user.getEntity().getLocation().getWorld().getName())) {
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else {
if (user.getHiddenReason() != null && user.getHiddenReason().equals(CosmeticUser.HiddenReason.WORLD)) {
user.showCosmetics();
}
user.showCosmetics(CosmeticUser.HiddenReason.WORLD);
}
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK) && user.getUserBackpackManager() != null) {
user.respawnBackpack();
@@ -145,7 +142,7 @@ public class PlayerGameListener implements Listener {
user.respawnBalloon();
}
user.updateCosmetic();
}, 1);
}, 2);
if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) || event.getCause().equals(PlayerTeleportEvent.TeleportCause.END_PORTAL)) return;
if (user.getUserEmoteManager().isPlayingEmote()) {
@@ -153,7 +150,7 @@ public class PlayerGameListener implements Listener {
}
}
@EventHandler(priority = EventPriority.LOW)
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPortalTeleport(PlayerPortalEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer().getUniqueId());
@@ -163,6 +160,12 @@ public class PlayerGameListener implements Listener {
return;
}
if (Settings.getDisabledWorlds().contains(user.getEntity().getLocation().getWorld().getName())) {
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else {
user.showCosmetics(CosmeticUser.HiddenReason.WORLD);
}
if (user.hasCosmeticInSlot(CosmeticSlot.BALLOON)) {
user.despawnBalloon();
@@ -195,12 +198,16 @@ public class PlayerGameListener implements Listener {
}
}
if (user.isInWardrobe()) {
user.leaveWardrobe();
if (WardrobeSettings.isPreventDamage()) {
event.setCancelled(true);
return;
}
if (WardrobeSettings.isDamagedKicked()) user.leaveWardrobe();
}
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerLook(PlayerMoveEvent event) {
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
@@ -278,6 +285,7 @@ public class PlayerGameListener implements Listener {
return;
}
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (user.getEntity() == null) return; // Player has likely logged off
user.updateCosmetic(CosmeticSlot.OFFHAND);
List<Player> viewers = HMCCPacketManager.getViewers(user.getEntity().getLocation());
if (viewers.isEmpty()) return;
@@ -306,7 +314,7 @@ public class PlayerGameListener implements Listener {
return;
}
if (event.getAction().equals(EntityPotionEffectEvent.Action.CLEARED) || event.getAction().equals(EntityPotionEffectEvent.Action.REMOVED)) {
user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.POTION);
return;
}
}
@@ -316,11 +324,12 @@ public class PlayerGameListener implements Listener {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
event.getPlayer().getInventory().setItem(event.getPreviousSlot(), event.getPlayer().getInventory().getItem(event.getPreviousSlot()));
//NMSHandlers.getHandler().slotUpdate(event.getPlayer(), event.getPreviousSlot());
if (user.hasCosmeticInSlot(CosmeticSlot.MAINHAND)) {
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
user.updateCosmetic(CosmeticSlot.MAINHAND);
}, 2);
}
// #84, Riptides mess with backpacks
ItemStack currentItem = event.getPlayer().getInventory().getItem(event.getNewSlot());
@@ -353,9 +362,7 @@ public class PlayerGameListener implements Listener {
if (Settings.getDisabledGamemodes().contains(event.getNewGameMode().toString())) {
user.hideCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
} else {
if (user.getHiddenReason() != null && user.getHiddenReason().equals(CosmeticUser.HiddenReason.GAMEMODE)) {
user.showCosmetics();
}
user.showCosmetics(CosmeticUser.HiddenReason.GAMEMODE);
}
}
@@ -414,8 +421,8 @@ public class PlayerGameListener implements Listener {
public void onPlayerUnVanish(HibiscusPlayerUnVanishEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
if (!user.getHidden()) return;
if (user.getHiddenReason().equals(CosmeticUser.HiddenReason.PLUGIN)) user.showCosmetics();
if (!user.isHidden()) return;
user.showCosmetics(CosmeticUser.HiddenReason.PLUGIN);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -433,6 +440,21 @@ public class PlayerGameListener implements Listener {
}
}
// These emote mostly handles emotes from other plugins, such as ItemsAdder
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerPlayEmote(HibiscusPlayerEmotePlayEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.hideCosmetics(CosmeticUser.HiddenReason.EMOTE);
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerEndEmote(HibiscusPlayerEmoteEndEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());
if (user == null) return;
user.showCosmetics(CosmeticUser.HiddenReason.EMOTE);
}
private void registerInventoryClickListener() {
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(HMCCosmeticsPlugin.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.WINDOW_CLICK) {
@Override
@@ -479,6 +501,10 @@ public class PlayerGameListener implements Listener {
if (!user.isInWardrobe()) {
for (Cosmetic cosmetic : user.getCosmetics()) {
if ((cosmetic instanceof CosmeticArmorType cosmeticArmorType)) {
boolean requireEmpty = Settings.getSlotOption(cosmeticArmorType.getEquipSlot()).isRequireEmpty();
boolean isAir = user.getPlayer().getInventory().getItem(cosmeticArmorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("Menu Fired (Checks) - " + cosmeticArmorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
items.put(HMCCInventoryUtils.getPacketArmorSlot(cosmeticArmorType.getEquipSlot()), user.getUserCosmeticItem(cosmeticArmorType));
}
}
@@ -529,9 +555,14 @@ public class PlayerGameListener implements Listener {
int slot = event.getPacket().getIntegers().read(2);
MessagesUtil.sendDebugMessages("SetSlot Slot " + slot);
if (slot == 45 && user.hasCosmeticInSlot(CosmeticSlot.OFFHAND) && player.getInventory().getItemInOffHand().getType().isAir()) {
event.getPacket().getItemModifier().write(0, user.getUserCosmeticItem(CosmeticSlot.OFFHAND));
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slot);
EquipmentSlot equipmentSlot = HMCCInventoryUtils.getPacketArmorSlot(slot);
if (cosmeticSlot == null || equipmentSlot == null) return;
if (!user.hasCosmeticInSlot(cosmeticSlot)) return;
if (Settings.getSlotOption(equipmentSlot).isRequireEmpty()) {
if (!player.getInventory().getItem(equipmentSlot).getType().isAir()) return;
}
event.getPacket().getItemModifier().write(0, user.getUserCosmeticItem(cosmeticSlot));
}
});
}
@@ -556,20 +587,17 @@ public class PlayerGameListener implements Listener {
if (user.getPlayer() == event.getPlayer()) continue; // When a player scrolls real fast, it messes up the mainhand. This fixes it
armor.set(i, new Pair<>(pair.getFirst(), user.getPlayer().getInventory().getItemInMainHand()));
}
case OFFHAND -> {
if (Settings.isCosmeticForceOffhandCosmeticShow() && user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) {
ItemStack item = user.getUserCosmeticItem(CosmeticSlot.OFFHAND);
if (item == null) continue;
Pair<EnumWrappers.ItemSlot, ItemStack> offhandPair = new Pair<>(EnumWrappers.ItemSlot.OFFHAND, item);
armor.set(i, offhandPair);
}
}
default -> {
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(HMCCInventoryUtils.getItemSlotToCosmeticSlot(pair.getFirst()));
EquipmentSlot slot = HMCCInventoryUtils.getEquipmentSlot(pair.getFirst());
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.getItemSlotToCosmeticSlot(pair.getFirst());
if (slot == null || cosmeticSlot == null) continue;
if (Settings.getSlotOption(slot).isRequireEmpty()
&& !user.getPlayer().getInventory().getItem(slot).getType().isAir()) continue;
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(cosmeticSlot);
if (cosmeticArmor == null) continue;
ItemStack item = user.getUserCosmeticItem(cosmeticArmor);
if (item == null) continue;
Pair<EnumWrappers.ItemSlot, ItemStack> armorPair = new Pair<>(HMCCInventoryUtils.itemBukkitSlot(cosmeticArmor.getEquipSlot()), item);
Pair<EnumWrappers.ItemSlot, ItemStack> armorPair = new Pair<>(HMCCInventoryUtils.itemBukkitSlot(slot), item);
armor.set(i, armorPair);
}
}
@@ -616,7 +644,8 @@ public class PlayerGameListener implements Listener {
}
if (!user.isInWardrobe()) return;
if (!user.getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return;
Menu menu = Menus.getDefaultMenu();
Menu menu = user.getWardrobeManager().getLastOpenMenu();
if (menu == null) return;
menu.openMenu(user);
event.setCancelled(true);

View File

@@ -13,6 +13,7 @@ import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticMainhandType;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserEmoteManager;
@@ -27,8 +28,10 @@ import me.lojosho.hibiscuscommons.util.InventoryUtils;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
@@ -54,9 +57,8 @@ public class CosmeticUser {
private final UserEmoteManager userEmoteManager;
// Cosmetic Settings/Toggles
private boolean hideCosmetics;
@Getter
private HiddenReason hiddenReason;
private final ArrayList<HiddenReason> hiddenReason = new ArrayList<>();
private final HashMap<CosmeticSlot, ItemStack> cachedCosmeticItems = new HashMap<>();
private final HashMap<CosmeticSlot, Color> colors = new HashMap<>();
public CosmeticUser(UUID uuid) {
@@ -70,7 +72,7 @@ public class CosmeticUser {
Runnable run = () -> {
MessagesUtil.sendDebugMessages("Tick[uuid=" + uniqueId + "]", Level.INFO);
updateCosmetic();
if (getHidden() && !getUserEmoteManager().isPlayingEmote()) MessagesUtil.sendActionBar(getPlayer(), "hidden-cosmetics");
if (isHidden() && !getUserEmoteManager().isPlayingEmote() && !getCosmetics().isEmpty()) MessagesUtil.sendActionBar(getPlayer(), "hidden-cosmetics");
};
int tickPeriod = Settings.getTickPeriod();
@@ -114,6 +116,7 @@ public class CosmeticUser {
playerCosmetics.put(cosmetic.getSlot(), cosmetic);
if (color != null) colors.put(cosmetic.getSlot(), color);
MessagesUtil.sendDebugMessages("addPlayerCosmetic[id=" + cosmetic.getId() + "]");
if (!isHidden()) {
if (cosmetic.getSlot() == CosmeticSlot.BACKPACK) {
CosmeticBackpackType backpackType = (CosmeticBackpackType) cosmetic;
spawnBackpack(backpackType);
@@ -123,6 +126,7 @@ public class CosmeticUser {
CosmeticBalloonType balloonType = (CosmeticBalloonType) cosmetic;
spawnBalloon(balloonType);
}
}
// API
PlayerCosmeticPostEquipEvent postEquipEvent = new PlayerCosmeticPostEquipEvent(this, cosmetic);
Bukkit.getPluginManager().callEvent(postEquipEvent);
@@ -153,6 +157,7 @@ public class CosmeticUser {
if (slot == CosmeticSlot.EMOTE) {
if (getUserEmoteManager().isPlayingEmote()) getUserEmoteManager().stopEmote(UserEmoteManager.StopEmoteReason.UNEQUIP);
}
cachedCosmeticItems.remove(slot);
colors.remove(slot);
playerCosmetics.remove(slot);
removeArmor(slot);
@@ -195,14 +200,18 @@ public class CosmeticUser {
for (Cosmetic cosmetic : getCosmetics()) {
if (cosmetic instanceof CosmeticArmorType armorType) {
if (getUserEmoteManager().isPlayingEmote() || isInWardrobe()) return;
if (!Settings.isCosmeticForceOffhandCosmeticShow()
&& armorType.getEquipSlot().equals(EquipmentSlot.OFF_HAND)
&& !getPlayer().getInventory().getItemInOffHand().getType().isAir()) continue;
if (!(getEntity() instanceof HumanEntity humanEntity)) return;
boolean requireEmpty = Settings.getSlotOption(armorType.getEquipSlot()).isRequireEmpty();
boolean isAir = humanEntity.getInventory().getItem(armorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("updateCosmetic (All) - " + armorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
items.put(HMCCInventoryUtils.getEquipmentSlot(armorType.getSlot()), armorType.getItem(this));
continue;
}
} else {
updateCosmetic(cosmetic.getSlot());
}
}
if (items.isEmpty() || getEntity() == null) return;
PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), items, HMCCPlayerUtils.getNearbyPlayers(getEntity().getLocation()));
MessagesUtil.sendDebugMessages("updateCosmetic (All) - end - " + items.size());
@@ -216,10 +225,14 @@ public class CosmeticUser {
public ItemStack getUserCosmeticItem(Cosmetic cosmetic) {
ItemStack item = null;
if (hideCosmetics) {
if (!hiddenReason.isEmpty()) {
if (cosmetic instanceof CosmeticBackpackType || cosmetic instanceof CosmeticBalloonType) return new ItemStack(Material.AIR);
return getPlayer().getInventory().getItem(HMCCInventoryUtils.getEquipmentSlot(cosmetic.getSlot()));
}
// Check if the item is cached. This helps with performance as we don't need to keep recreating the item
if (cachedCosmeticItems.containsKey(cosmetic.getSlot())) {
return cachedCosmeticItems.get(cosmetic.getSlot());
}
if (cosmetic instanceof CosmeticArmorType armorType) {
item = armorType.getItem(this, cosmetic.getItem());
}
@@ -242,6 +255,10 @@ public class CosmeticUser {
//MessagesUtil.sendDebugMessages("GetUserCosemticUser Item is null");
return new ItemStack(Material.AIR);
}
// Check if the item is cached. This helps with performance as we don't need to keep recreating the item
if (cachedCosmeticItems.containsKey(cosmetic.getSlot())) {
return cachedCosmeticItems.get(cosmetic.getSlot());
}
if (item.hasItemMeta()) {
ItemMeta itemMeta = item.getItemMeta();
@@ -289,6 +306,15 @@ public class CosmeticUser {
potionMeta.setColor(color);
} else if (itemMeta instanceof MapMeta mapMeta) {
mapMeta.setColor(color);
} else if (itemMeta instanceof FireworkEffectMeta fireworkMeta) {
fireworkMeta.setEffect(
FireworkEffect.builder()
.with(FireworkEffect.Type.BALL)
.withColor(color)
.trail(false)
.flicker(false)
.build()
);
}
}
itemMeta.getPersistentDataContainer().set(HMCCInventoryUtils.getCosmeticKey(), PersistentDataType.STRING, cosmetic.getId());
@@ -296,6 +322,7 @@ public class CosmeticUser {
item.setItemMeta(itemMeta);
}
cachedCosmeticItems.put(cosmetic.getSlot(), item);
return item;
}
@@ -347,6 +374,7 @@ public class CosmeticUser {
if (!getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return;
getWardrobeManager().setWardrobeStatus(UserWardrobeManager.WardrobeStatus.STOPPING);
getWardrobeManager().setLastOpenMenu(Menus.getDefaultMenu());
if (WardrobeSettings.isEnabledTransition() && !ejected) {
MessagesUtil.sendTitle(
@@ -419,7 +447,7 @@ public class CosmeticUser {
if (!hasCosmeticInSlot(CosmeticSlot.BACKPACK)) return;
final Cosmetic cosmetic = getCosmetic(CosmeticSlot.BACKPACK);
despawnBackpack();
if (hideCosmetics) return;
if (!hiddenReason.isEmpty()) return;
spawnBackpack((CosmeticBackpackType) cosmetic);
MessagesUtil.sendDebugMessages("Respawned Backpack for " + getEntity().getName());
}
@@ -428,7 +456,7 @@ public class CosmeticUser {
if (!hasCosmeticInSlot(CosmeticSlot.BALLOON)) return;
final Cosmetic cosmetic = getCosmetic(CosmeticSlot.BALLOON);
despawnBalloon();
if (hideCosmetics) return;
if (!hiddenReason.isEmpty()) return;
spawnBalloon((CosmeticBalloonType) cosmetic);
MessagesUtil.sendDebugMessages("Respawned Balloon for " + getEntity().getName());
}
@@ -506,15 +534,13 @@ public class CosmeticUser {
}
public void hideCosmetics(HiddenReason reason) {
if (hideCosmetics) return;
PlayerCosmeticHideEvent event = new PlayerCosmeticHideEvent(this, reason);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
hideCosmetics = true;
hiddenReason = reason;
if (!hiddenReason.contains(reason)) hiddenReason.add(reason);
if (hasCosmeticInSlot(CosmeticSlot.BALLOON)) {
despawnBalloon();
//getBalloonManager().removePlayerFromModel(getPlayer());
@@ -527,8 +553,16 @@ public class CosmeticUser {
MessagesUtil.sendDebugMessages("HideCosmetics");
}
public void showCosmetics() {
if (!hideCosmetics) return;
/**
* This is used to silently add a hidden flag to the user. This will not trigger any events or checks, nor do anything else
* @param reason
*/
public void silentlyAddHideFlag(HiddenReason reason) {
if (!hiddenReason.contains(reason)) hiddenReason.add(reason);
}
public void showCosmetics(HiddenReason reason) {
if (hiddenReason.isEmpty()) return;
PlayerCosmeticShowEvent event = new PlayerCosmeticShowEvent(this);
Bukkit.getPluginManager().callEvent(event);
@@ -536,8 +570,8 @@ public class CosmeticUser {
return;
}
hideCosmetics = false;
hiddenReason = HiddenReason.NONE;
hiddenReason.remove(reason);
if (isHidden()) return;
if (hasCosmeticInSlot(CosmeticSlot.BALLOON)) {
if (!isBalloonSpawned()) respawnBalloon();
CosmeticBalloonType balloonType = (CosmeticBalloonType) getCosmetic(CosmeticSlot.BALLOON);
@@ -555,8 +589,30 @@ public class CosmeticUser {
MessagesUtil.sendDebugMessages("ShowCosmetics");
}
/**
* This method is deprecated and will be removed in the future. Use {@link #isHidden()} instead.
* @return
*/
@Deprecated(since = "2.7.2-DEV", forRemoval = true)
public boolean getHidden() {
return this.hideCosmetics;
return !hiddenReason.isEmpty();
}
public boolean isHidden() {
return !hiddenReason.isEmpty();
}
public boolean isHidden(HiddenReason reason) {
return hiddenReason.contains(reason);
}
public List<HiddenReason> getHiddenReasons() {
return hiddenReason;
}
public void clearHiddenReasons() {
hiddenReason.clear();
}
public enum HiddenReason {
@@ -568,6 +624,7 @@ public class CosmeticUser {
COMMAND,
EMOTE,
GAMEMODE,
WORLD
WORLD,
DISABLED
}
}

View File

@@ -4,6 +4,7 @@ import com.google.common.collect.HashBiMap;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
@@ -11,31 +12,58 @@ import java.util.UUID;
public class CosmeticUsers {
private static HashBiMap<UUID, CosmeticUser> COSMETIC_USERS = HashBiMap.create();
private static final HashBiMap<UUID, CosmeticUser> COSMETIC_USERS = HashBiMap.create();
public static void addUser(CosmeticUser user) {
/**
* Adds a user to the Hashmap of stored CosmeticUsers. This will not override an entry if it already exists. If you need to override, delete then add.
* @param user The user to add to the HashMap.
*/
public static void addUser(@NotNull CosmeticUser user) {
if (COSMETIC_USERS.containsKey(user.getUniqueId())) return; // do not add if already exists
COSMETIC_USERS.put(user.getUniqueId(), user);
}
/**
* Removes a CosmeticUser from the Hashmap
* @param uuid The UUID to remove.
*/
public static void removeUser(UUID uuid) {
COSMETIC_USERS.remove(uuid);
}
public static void removeUser(CosmeticUser user) {
COSMETIC_USERS.remove(user);
/**
* Removes a CosmeticUser from the hashmap by their CosmeticUser method
* @param user The user to be removed (will get their UUID from this class)
*/
public static void removeUser(@NotNull CosmeticUser user) {
COSMETIC_USERS.remove(user.getUniqueId());
}
/**
* This method allows you to get a CosmeticUser from their UUID. If you are using not internally, HIGHLY recommend to use the API implementation of this.
* @param uuid The UUID of the user that you wish to lookup.
* @return Returns the user if there is a valid user, returns null if not.
*/
@Nullable
public static CosmeticUser getUser(UUID uuid) {
return COSMETIC_USERS.get(uuid);
}
/**
* This method allows you to get a CosmeticUser from just using the player class. This just allows you to have a bit less boilerplate.
* @param player The player to lookup (will take their UUID from the class)
* @return Returns the user if there is a vlaid user, returns null if not.
*/
@Nullable
public static CosmeticUser getUser(Player player) {
public static CosmeticUser getUser(@NotNull Player player) {
return COSMETIC_USERS.get(player.getUniqueId());
}
/**
* This method gets the CosmeticUser from an entity id (said entity must be a player). This is not ideal, as it requires the plugin to go through all entities, but it's a possibility.
* @param entityId The entity ID in an integer.
* @return The cosmetic user if there is an entity id associated with that.
*/
@Nullable
public static CosmeticUser getUser(int entityId) {
Entity entity = HMCCServerUtils.getEntity(entityId);
@@ -44,6 +72,11 @@ public class CosmeticUsers {
return COSMETIC_USERS.get(player.getUniqueId());
}
/**
* Gets all the values for CosmeticUsers to allow you to iterate over everyone.
* @return CosmeticUsers in a set. This will never be null, but might be empty.
*/
@NotNull
public static Set<CosmeticUser> values() {
return COSMETIC_USERS.values();
}

View File

@@ -1,24 +1,28 @@
package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.misc.ItemDisplayMetadata;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.modelengine.api.ModelEngineAPI;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.util.ServerUtils;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Level;
@@ -27,23 +31,26 @@ public class UserBackpackManager {
@Getter
private boolean backpackHidden;
@Getter
private int invisibleArmorStand;
private int itemDisplayId;
private ArrayList<Integer> particleCloud = new ArrayList<>();
@Getter
private final CosmeticUser user;
@Getter
private UserEntity entityManager;
//@Getter @Setter
//private boolean inBlock;
public UserBackpackManager(CosmeticUser user) {
this.user = user;
this.backpackHidden = false;
this.invisibleArmorStand = ServerUtils.getNextEntityId();
//this.inBlock = false;
this.itemDisplayId = ServerUtils.getNextEntityId();
this.entityManager = new UserEntity(user.getUniqueId());
this.entityManager.refreshViewers(user.getEntity().getLocation());
if (user.getEntity() != null) this.entityManager.refreshViewers(user.getEntity().getLocation()); // Fixes an issue where a player, who somehow removes their potions, but doesn't have an entity produces an NPE (it's dumb)
}
public int getFirstArmorStandId() {
return invisibleArmorStand;
public int getFirstItemDisplayId() {
return itemDisplayId;
}
public void spawnBackpack(CosmeticBackpackType cosmeticBackpackType) {
@@ -53,11 +60,12 @@ public class UserBackpackManager {
}
private void spawn(CosmeticBackpackType cosmeticBackpackType) {
getEntityManager().setIds(List.of(invisibleArmorStand));
getEntityManager().teleport(user.getEntity().getLocation());
Location entityLoc = user.getEntity().getLocation();
entityLoc.setPitch(0f);
getEntityManager().setIds(List.of(itemDisplayId));
getEntityManager().teleport(entityLoc);
List<Player> outsideViewers = getEntityManager().getViewers();
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), getFirstArmorStandId(), EntityType.ARMOR_STAND, UUID.randomUUID(), getEntityManager().getViewers());
HMCCPacketManager.sendArmorstandMetadata(getFirstArmorStandId(), outsideViewers);
HMCCPacketManager.sendEntitySpawnPacket(entityLoc, getFirstItemDisplayId(), EntityType.ITEM_DISPLAY, UUID.randomUUID(), getEntityManager().getViewers());
Entity entity = user.getEntity();
@@ -67,12 +75,12 @@ public class UserBackpackManager {
passengerIDs[i] = entity.getPassengers().get(i).getEntityId();
}
passengerIDs[passengerIDs.length - 1] = this.getFirstArmorStandId();
passengerIDs[passengerIDs.length - 1] = this.getFirstItemDisplayId();
ArrayList<Player> owner = new ArrayList<>();
if (user.getPlayer() != null) owner.add(user.getPlayer());
if (cosmeticBackpackType.isFirstPersonCompadible()) {
if (cosmeticBackpackType.isFirstPersonCompatible()) {
for (int i = particleCloud.size(); i < cosmeticBackpackType.getHeight(); i++) {
int entityId = ServerUtils.getNextEntityId();
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), entityId, EntityType.AREA_EFFECT_CLOUD, UUID.randomUUID());
@@ -84,10 +92,11 @@ public class UserBackpackManager {
if (i == 0) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), particleCloud.get(i), owner);
else HMCCPacketManager.sendRidingPacket(particleCloud.get(i - 1), particleCloud.get(i) , owner);
}
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), user.getUserBackpackManager().getFirstArmorStandId(), owner);
if (!user.getHidden()) PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(cosmeticBackpackType, cosmeticBackpackType.getFirstPersonBackpack()), owner);
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1),getFirstItemDisplayId(), owner);
if (!user.isHidden()) HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), cosmeticBackpackType.getFirstPersonMetadata(), user.getUserCosmeticItem(cosmeticBackpackType, cosmeticBackpackType.getFirstPersonBackpack()), outsideViewers);
}
PacketManager.equipmentSlotUpdate(getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(cosmeticBackpackType), outsideViewers);
HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), cosmeticBackpackType.getMetadata(), user.getUserCosmeticItem(cosmeticBackpackType), outsideViewers);
HMCCPacketManager.sendRidingPacket(entity.getEntityId(), passengerIDs, outsideViewers);
// No one should be using ME because it barely works but some still use it, so it's here
@@ -108,17 +117,17 @@ public class UserBackpackManager {
}
public void despawnBackpack() {
HMCCPacketManager.sendEntityDestroyPacket(invisibleArmorStand, getEntityManager().getViewers());
IntList entityIds = IntArrayList.of(itemDisplayId);
if (particleCloud != null) {
for (Integer entityId : particleCloud) {
HMCCPacketManager.sendEntityDestroyPacket(entityId, getEntityManager().getViewers());
}
entityIds.addAll(particleCloud);
this.particleCloud = null;
}
HMCCPacketManager.sendEntityDestroyPacket(entityIds, getEntityManager().getViewers());
}
public void hideBackpack() {
if (user.getHidden()) return;
if (user.isHidden()) return;
//getArmorStand().getEquipment().clear();
backpackHidden = true;
}
@@ -140,11 +149,42 @@ public class UserBackpackManager {
}
public void setItem(ItemStack item) {
PacketManager.equipmentSlotUpdate(getFirstArmorStandId(), EquipmentSlot.HEAD, item, getEntityManager().getViewers());
ItemDisplayMetadata metadata = Optional.ofNullable((CosmeticBackpackType) user.getCosmetic(CosmeticSlot.BACKPACK)).map(CosmeticBackpackType::getMetadata).orElse(new ItemDisplayMetadata());
HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), metadata, item, getEntityManager().getViewers());
}
public void clearItems() {
ItemStack item = new ItemStack(Material.AIR);
PacketManager.equipmentSlotUpdate(getFirstArmorStandId(), EquipmentSlot.HEAD, item, getEntityManager().getViewers());
//PacketManager.equipmentSlotUpdate(getFirstItemDisplayId(), EquipmentSlot.HEAD, item, getEntityManager().getViewers());
HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), item, getEntityManager().getViewers());
}
/**
* Refreshes the block detection for the backpack
* @param outsideViewers
* @return true if the entity was updated, false if not
*//*
public boolean refreshBlock(List<Player> outsideViewers) {
if (Settings.isBackpackBlockDetection()) {
if (isInBlock() && checkBlock()) {
HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), false, outsideViewers);
setInBlock(false);
return true;
}
if (!isInBlock() && !checkBlock()) {
HMCCPacketManager.sendItemDisplayMetadata(getFirstItemDisplayId(), true, outsideViewers);
setInBlock(true);
return true;
}
}
return false;
}
public boolean checkBlock() {
if (Settings.isBackpackBlockDetection()) {
Block block = getEntityManager().getLocation().clone().add(0, 1.5, 0).getBlock();
return block.getType().isAir();
}
return false;
}*/
}

View File

@@ -205,7 +205,7 @@ public class UserBalloonManager {
CosmeticUser viewer = CosmeticUsers.getUser(player.getUniqueId());
if (user.getPlayer() == player) {
return (!user.getHidden());
return (!user.isHidden());
} else {
if (user.isInWardrobe()) return false;
MessagesUtil.sendDebugMessages("playerCheck - Not Same Player");
@@ -214,6 +214,6 @@ public class UserBalloonManager {
return false;
}
}
return (!user.getHidden());
return (!user.isHidden());
}
}

View File

@@ -23,13 +23,13 @@ public class UserEmoteModel extends PlayerModel {
private final CosmeticUser user;
private String emotePlaying;
private final int armorStandId;
private final int itemDisplayId;
private GameMode originalGamemode;
public UserEmoteModel(@NotNull CosmeticUser user) {
super(user.getPlayer());
this.user = user;
armorStandId = ServerUtils.getNextEntityId();
itemDisplayId = ServerUtils.getNextEntityId();
getRangeManager().setRenderDistance(Settings.getViewDistance());
}
@@ -75,12 +75,12 @@ public class UserEmoteModel extends PlayerModel {
MessagesUtil.sendMessage(player, "emote-blocked");
}
HMCCPacketManager.sendEntitySpawnPacket(thirdPersonLocation, armorStandId, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer);
HMCCPacketManager.sendInvisibilityPacket(armorStandId, viewer);
HMCCPacketManager.sendLookPacket(armorStandId, thirdPersonLocation, viewer);
HMCCPacketManager.sendEntitySpawnPacket(thirdPersonLocation, itemDisplayId, EntityType.ITEM_DISPLAY, UUID.randomUUID(), viewer);
//HMCCPacketManager.sendInvisibilityPacket(itemDisplayId, viewer);
HMCCPacketManager.sendLookPacket(itemDisplayId, thirdPersonLocation, viewer);
HMCCPacketManager.gamemodeChangePacket(player, 3);
HMCCPacketManager.sendCameraPacket(armorStandId, viewer);
HMCCPacketManager.sendCameraPacket(itemDisplayId, viewer);
}
@@ -115,7 +115,7 @@ public class UserEmoteModel extends PlayerModel {
int entityId = player.getEntityId();
HMCCPacketManager.sendCameraPacket(entityId, viewer);
HMCCPacketManager.sendEntityDestroyPacket(armorStandId, viewer);
HMCCPacketManager.sendEntityDestroyPacket(itemDisplayId, viewer);
if (this.originalGamemode != null) {
HMCCPacketManager.gamemodeChangePacket(player, HMCCServerUtils.convertGamemode(this.originalGamemode));
player.setGameMode(this.originalGamemode);
@@ -124,7 +124,7 @@ public class UserEmoteModel extends PlayerModel {
if (user.getPlayer() != null) player.setInvisible(false);
user.getUserEmoteManager().despawnTextEntity();
user.showPlayer();
user.showCosmetics();
user.showCosmetics(CosmeticUser.HiddenReason.EMOTE);
});
}

View File

@@ -5,6 +5,8 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
@@ -45,6 +47,7 @@ public class UserEntity {
for (Player player : players) {
CosmeticUser user = CosmeticUsers.getUser(player);
IntList ids = new IntArrayList(this.ids);
if (user != null && owner != user.getUniqueId() && user.isInWardrobe()) { // Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
removePlayers.add(player);
HMCCPacketManager.sendEntityDestroyPacket(ids, List.of(player));

View File

@@ -6,14 +6,18 @@ import com.hibiscusmc.hmccosmetics.config.WardrobeLocation;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.misc.ItemDisplayMetadata;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import net.kyori.adventure.audience.Audience;
@@ -31,10 +35,7 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class UserWardrobeManager {
@@ -42,7 +43,7 @@ public class UserWardrobeManager {
@Getter
private final int NPC_ID;
@Getter
private final int ARMORSTAND_ID;
private final int ITEM_DISPLAY_ID;
@Getter
private final UUID WARDROBE_UUID;
@Getter
@@ -67,10 +68,13 @@ public class UserWardrobeManager {
private boolean active;
@Getter
private WardrobeStatus wardrobeStatus;
@Getter
@Setter
private Menu lastOpenMenu;
public UserWardrobeManager(CosmeticUser user, Wardrobe wardrobe) {
NPC_ID = me.lojosho.hibiscuscommons.util.ServerUtils.getNextEntityId();
ARMORSTAND_ID = me.lojosho.hibiscuscommons.util.ServerUtils.getNextEntityId();
ITEM_DISPLAY_ID = me.lojosho.hibiscuscommons.util.ServerUtils.getNextEntityId();
WARDROBE_UUID = UUID.randomUUID();
this.user = user;
@@ -82,6 +86,7 @@ public class UserWardrobeManager {
this.npcLocation = wardrobeLocation.getNpcLocation();
wardrobeStatus = WardrobeStatus.SETUP;
this.lastOpenMenu = Menus.getDefaultMenu();
}
public void start() {
@@ -94,6 +99,7 @@ public class UserWardrobeManager {
}
user.hidePlayer();
if (!Bukkit.getServer().getAllowFlight()) player.setAllowFlight(true);
List<Player> viewer = Collections.singletonList(player);
List<Player> outsideViewers = HMCCPacketManager.getViewers(viewingLocation);
outsideViewers.remove(player);
@@ -101,16 +107,16 @@ public class UserWardrobeManager {
MessagesUtil.sendMessage(player, "opened-wardrobe");
Runnable run = () -> {
// Armorstand
HMCCPacketManager.sendEntitySpawnPacket(viewingLocation, ARMORSTAND_ID, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer);
HMCCPacketManager.sendArmorstandMetadata(ARMORSTAND_ID, viewer);
HMCCPacketManager.sendLookPacket(ARMORSTAND_ID, viewingLocation, viewer);
// ItemDisplay
HMCCPacketManager.sendEntitySpawnPacket(viewingLocation, ITEM_DISPLAY_ID, EntityType.ITEM_DISPLAY, UUID.randomUUID(), viewer);
HMCCPacketManager.sendItemDisplayMetadata(ITEM_DISPLAY_ID, new ItemStack(Material.AIR), viewer);
HMCCPacketManager.sendLookPacket(ITEM_DISPLAY_ID, viewingLocation, viewer);
// Player
user.getPlayer().teleport(viewingLocation, PlayerTeleportEvent.TeleportCause.PLUGIN);
user.getPlayer().setInvisible(true);
HMCCPacketManager.gamemodeChangePacket(player, 3);
HMCCPacketManager.sendCameraPacket(ARMORSTAND_ID, viewer);
HMCCPacketManager.sendCameraPacket(ITEM_DISPLAY_ID, viewer);
// NPC
npcName = "WardrobeNPC-" + NPC_ID;
@@ -135,11 +141,13 @@ public class UserWardrobeManager {
// Misc
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) {
// Maybe null as backpack maybe despawned before entering
if (user.getUserBackpackManager() == null) user.respawnBackpack();
UserBackpackManager userBackpackManager = user.getUserBackpackManager();
if (userBackpackManager == null) user.respawnBackpack();
if (user.isBackpackSpawned()) {
user.getUserBackpackManager().getEntityManager().teleport(npcLocation.clone().add(0, 2, 0));
PacketManager.equipmentSlotUpdate(user.getUserBackpackManager().getFirstArmorStandId(), EquipmentSlot.HEAD, user.getUserCosmeticItem(user.getCosmetic(CosmeticSlot.BACKPACK)), viewer);
HMCCPacketManager.ridingMountPacket(NPC_ID, user.getUserBackpackManager().getFirstArmorStandId(), viewer);
userBackpackManager.getEntityManager().teleport(npcLocation.clone());
CosmeticBackpackType backpackCosmetic = (CosmeticBackpackType) user.getCosmetic(CosmeticSlot.BACKPACK);
HMCCPacketManager.sendItemDisplayMetadata(ITEM_DISPLAY_ID, backpackCosmetic.getMetadata(), user.getUserCosmeticItem(backpackCosmetic), viewer);
HMCCPacketManager.ridingMountPacket(NPC_ID, userBackpackManager.getFirstItemDisplayId(), viewer);
}
}
@@ -160,7 +168,7 @@ public class UserWardrobeManager {
if (WardrobeSettings.isEnabledBossbar()) {
float progress = WardrobeSettings.getBossbarProgress();
Component message = MessagesUtil.processStringNoKey(WardrobeSettings.getBossbarMessage());
Component message = MessagesUtil.processStringNoKey(player, WardrobeSettings.getBossbarMessage());
bossBar = BossBar.bossBar(message, progress, WardrobeSettings.getBossbarColor(), WardrobeSettings.getBossbarOverlay());
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
@@ -202,7 +210,9 @@ public class UserWardrobeManager {
List<Player> outsideViewers = HMCCPacketManager.getViewers(viewingLocation);
outsideViewers.remove(player);
if (player != null) MessagesUtil.sendMessage(player, "closed-wardrobe");
if (player == null) return;
if (!Bukkit.getServer().getAllowFlight()) player.setAllowFlight(false);
MessagesUtil.sendMessage(player, "closed-wardrobe");
Runnable run = () -> {
this.active = false;
@@ -226,7 +236,7 @@ public class UserWardrobeManager {
user.getPlayer().setInvisible(false);
// Armorstand
HMCCPacketManager.sendEntityDestroyPacket(ARMORSTAND_ID, viewer); // Sucess
HMCCPacketManager.sendEntityDestroyPacket(ITEM_DISPLAY_ID, viewer); // Sucess
//PacketManager.sendEntityDestroyPacket(player.getEntityId(), viewer); // Success
if (WardrobeSettings.isForceExitGamemode()) {
@@ -252,9 +262,17 @@ public class UserWardrobeManager {
player.teleport(Objects.requireNonNullElseGet(exitLocation, () -> player.getWorld().getSpawnLocation()), PlayerTeleportEvent.TeleportCause.PLUGIN);
if (WardrobeSettings.isEquipPumpkin()) {
PacketManager.equipmentSlotUpdate(user.getPlayer().getEntityId(), EquipmentSlot.HEAD, player.getInventory().getHelmet(), viewer);
HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for (EquipmentSlot slot : HMCCInventoryUtils.getPlayerArmorSlots()) {
ItemStack item = player.getInventory().getItem(slot);
items.put(slot, item);
}
/*
if (WardrobeSettings.isEquipPumpkin()) {
items.put(EquipmentSlot.HEAD, player.getInventory().getHelmet());
}
*/
HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), items, viewer);
if (WardrobeSettings.isEnabledBossbar()) {
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
@@ -301,10 +319,10 @@ public class UserWardrobeManager {
}
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK) && user.getUserBackpackManager() != null) {
HMCCPacketManager.sendTeleportPacket(user.getUserBackpackManager().getFirstArmorStandId(), location, false, viewer);
HMCCPacketManager.ridingMountPacket(NPC_ID, user.getUserBackpackManager().getFirstArmorStandId(), viewer);
HMCCPacketManager.sendTeleportPacket(user.getUserBackpackManager().getFirstItemDisplayId(), location, false, viewer);
HMCCPacketManager.ridingMountPacket(NPC_ID, user.getUserBackpackManager().getFirstItemDisplayId(), viewer);
user.getUserBackpackManager().getEntityManager().setRotation(nextyaw);
HMCCPacketManager.sendEntityDestroyPacket(user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
HMCCPacketManager.sendEntityDestroyPacket(user.getUserBackpackManager().getFirstItemDisplayId(), outsideViewers);
}
if (user.hasCosmeticInSlot(CosmeticSlot.BALLOON) && user.isBalloonSpawned()) {

View File

@@ -11,6 +11,9 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public class HMCCInventoryUtils {
/**
@@ -153,6 +156,32 @@ public class HMCCInventoryUtils {
}
}
public static EquipmentSlot getEquipmentSlot(@NotNull EnumWrappers.ItemSlot slot) {
switch (slot) {
case HEAD -> {
return EquipmentSlot.HEAD;
}
case CHEST -> {
return EquipmentSlot.CHEST;
}
case LEGS -> {
return EquipmentSlot.LEGS;
}
case FEET -> {
return EquipmentSlot.FEET;
}
case OFFHAND -> {
return EquipmentSlot.OFF_HAND;
}
case MAINHAND -> {
return EquipmentSlot.HAND;
}
default -> {
return null;
}
}
}
public static boolean isCosmeticItem(ItemStack itemStack) {
if (itemStack == null) return false;
itemStack = itemStack.clone();
@@ -163,4 +192,12 @@ public class HMCCInventoryUtils {
public static NamespacedKey getCosmeticKey() {
return new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmetic");
}
/**
* This returns all the slots a player can have on them. In 1.20.6+, the enum includes BODY, which is not a valid slot for a player.
* @return A list of all the slots a player can have on them
*/
public static List<EquipmentSlot> getPlayerArmorSlots() {
return Arrays.asList(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET, EquipmentSlot.OFF_HAND, EquipmentSlot.HAND);
}
}

View File

@@ -0,0 +1,49 @@
package com.hibiscusmc.hmccosmetics.util.misc;
import org.bukkit.Material;
import org.bukkit.entity.Display;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.HashMap;
import java.util.Map;
public class ItemDisplayMetadata {
public Vector3f translation;
public Vector3f scale;
public Quaternionf rotationLeft;
public Quaternionf rotationRight;
public Display.Billboard billboard;
public int skyLight;
public float viewRange;
public float width;
public float height;
public ItemDisplay.ItemDisplayTransform displayTransform;
public ItemStack itemStack;
public ItemDisplayMetadata() {
this.translation = new Vector3f();
this.scale = new Vector3f(1.0f, 1.0f, 1.0f);
this.rotationLeft = new Quaternionf();
this.rotationRight = new Quaternionf();
this.skyLight = 15;
this.viewRange = 1.0f;
this.width = 0.0f;
this.height = 0.0f;
this.displayTransform = ItemDisplay.ItemDisplayTransform.NONE;
this.itemStack = new ItemStack(Material.AIR);
}
public ItemDisplayMetadata setFixed() {
this.billboard = Display.Billboard.FIXED;
return this;
}
public ItemDisplayMetadata setVertical() {
this.billboard = Display.Billboard.VERTICAL;
return this;
}
}

View File

@@ -12,17 +12,22 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.misc.ItemDisplayMetadata;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerNamedEntitySpawn;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerPlayerInfo;
import com.hibiscusmc.hmccosmetics.util.packets.wrappers.WrapperPlayServerRelEntityMove;
import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Display;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.*;
@@ -44,16 +49,7 @@ public class HMCCPacketManager extends PacketManager {
final UUID uuid,
final @NotNull List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY);
packet.getModifier().writeDefaults();
packet.getUUIDs().write(0, uuid);
packet.getIntegers().write(0, entityId);
packet.getEntityTypeModifier().write(0, entityType);
packet.getDoubles().
write(0, location.getX()).
write(1, location.getY()).
write(2, location.getZ());
for (Player p : sendTo) sendPacket(p, packet);
PacketManager.sendEntitySpawnPacket(location, entityId, entityType, uuid, sendTo);
}
public static void equipmentSlotUpdate(
@@ -62,7 +58,7 @@ public class HMCCPacketManager extends PacketManager {
List<Player> sendTo
) {
HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for (EquipmentSlot slot : EquipmentSlot.values()) {
for (EquipmentSlot slot : HMCCInventoryUtils.getPlayerArmorSlots()) {
ItemStack item = player.getInventory().getItem(slot);
if (empty) item = new ItemStack(Material.AIR);
items.put(slot, item);
@@ -91,31 +87,22 @@ public class HMCCPacketManager extends PacketManager {
CosmeticSlot cosmeticSlot,
List<Player> sendTo
) {
if (cosmeticSlot == CosmeticSlot.BACKPACK || cosmeticSlot == CosmeticSlot.BALLOON || cosmeticSlot == CosmeticSlot.EMOTE) return;
if (cosmeticSlot == CosmeticSlot.BACKPACK || cosmeticSlot == CosmeticSlot.CUSTOM || cosmeticSlot == CosmeticSlot.BALLOON || cosmeticSlot == CosmeticSlot.EMOTE) return;
equipmentSlotUpdate(entityId, HMCCInventoryUtils.getEquipmentSlot(cosmeticSlot), user.getUserCosmeticItem(cosmeticSlot), sendTo);
}
public static void sendArmorstandMetadata(
int entityId,
List<Player> sendTo
) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20);
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x10);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x20));
wrappedDataValueList.add(new WrappedDataValue(15, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x10));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
public static void sendItemDisplayMetadata(int entityId, ItemStack itemStack, List<Player> sendTo) {
ItemDisplayMetadata metadata = new ItemDisplayMetadata();
PacketManager.sendItemDisplayMetadataPacket(entityId, metadata.translation, metadata.scale, metadata.rotationLeft, metadata.rotationRight, metadata.billboard, 0, metadata.skyLight, metadata.viewRange, metadata.width, metadata.height, metadata.displayTransform, itemStack, sendTo);
}
for (Player p : sendTo) sendPacket(p, packet);
public static void sendItemDisplayMetadata(int entityId, ItemDisplayMetadata metadata, List<Player> sendTo) {
PacketManager.sendItemDisplayMetadataPacket(entityId, metadata.translation, metadata.scale, metadata.rotationLeft, metadata.rotationRight, metadata.billboard, 0, metadata.skyLight, metadata.viewRange, metadata.width, metadata.height, metadata.displayTransform, metadata.itemStack, sendTo);
}
public static void sendItemDisplayMetadata(int entityId, ItemDisplayMetadata metadata, ItemStack itemStack, List<Player> sendTo) {
PacketManager.sendItemDisplayMetadataPacket(entityId, metadata.translation, metadata.scale, metadata.rotationLeft, metadata.rotationRight, metadata.billboard, 0, metadata.skyLight, metadata.viewRange, metadata.width, metadata.height, metadata.displayTransform, itemStack, sendTo);
}
public static void sendInvisibilityPacket(
@@ -125,16 +112,10 @@ public class HMCCPacketManager extends PacketManager {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x20));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (Player p : sendTo) sendPacket(p, packet);
}
@@ -145,19 +126,13 @@ public class HMCCPacketManager extends PacketManager {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, entityId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20);
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(8, WrappedDataWatcher.Registry.get(Float.class)), 0f);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(0, WrappedDataWatcher.Registry.get(Byte.class), (byte) 0x20));
wrappedDataValueList.add(new WrappedDataValue(8, WrappedDataWatcher.Registry.get(Float.class), 0f));
//wrappedDataValueList.add(new WrappedDataValue(11, WrappedDataWatcher.Registry.get(Integer.class), 21));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (Player p : sendTo) sendPacket(p, packet);
}
@@ -266,7 +241,7 @@ public class HMCCPacketManager extends PacketManager {
final int entityId,
final @NotNull List<Player> sendTo
) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R3") || HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R1")) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R3") || HMCCosmeticsAPI.getNMSVersion().contains("v1_20_R1")) {
WrapperPlayServerNamedEntitySpawn wrapper = new WrapperPlayServerNamedEntitySpawn();
wrapper.setEntityID(entityId);
wrapper.setPlayerUUID(uuid);
@@ -303,22 +278,13 @@ public class HMCCPacketManager extends PacketManager {
WrappedGameProfile wrappedGameProfile = new WrappedGameProfile(uuid, name);
WrappedSignedProperty skinData = HMCCPlayerUtils.getSkin(skinnedPlayer);
if (skinData != null) wrappedGameProfile.getProperties().put("textures", skinData);
// For sor some reason <1.19.2 handles it on the 0 field index, newer versions handles it on the 1
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
info.getHandle().getPlayerInfoDataLists().write(0, Collections.singletonList(new PlayerInfoData(
wrappedGameProfile,
0,
EnumWrappers.NativeGameMode.CREATIVE,
WrappedChatComponent.fromText(name)
)));
} else {
info.getHandle().getPlayerInfoDataLists().write(1, Collections.singletonList(new PlayerInfoData(
wrappedGameProfile,
0,
EnumWrappers.NativeGameMode.CREATIVE,
WrappedChatComponent.fromText(name)
)));
}
for (final Player p : sendTo) sendPacket(p, info.getHandle());
}
@@ -346,20 +312,12 @@ public class HMCCPacketManager extends PacketManager {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
packet.getModifier().writeDefaults();
packet.getIntegers().write(0, playerId);
WrappedDataWatcher wrapper = new WrappedDataWatcher();
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
wrapper.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(17, WrappedDataWatcher.Registry.get(Byte.class)), mask);
packet.getWatchableCollectionModifier().write(0, wrapper.getWatchableObjects());
} else {
final List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataValueList.add(new WrappedDataValue(17, WrappedDataWatcher.Registry.get(Byte.class), mask));
packet.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
for (final Player p : sendTo) {
sendPacket(p, packet);
}
for (final Player p : sendTo) sendPacket(p, packet);
}
/**
@@ -374,21 +332,6 @@ public class HMCCPacketManager extends PacketManager {
final UUID uuid,
final List<Player> sendTo
) {
if (HMCCosmeticsAPI.getNMSVersion().contains("v1_18_R2") || HMCCosmeticsAPI.getNMSVersion().contains("v1_19_R1")) {
WrapperPlayServerPlayerInfo info = new WrapperPlayServerPlayerInfo();
// Remove player is deprecated on 1.19.3+, but we still need to support 1.18.2
info.setAction(EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
String name = "Mannequin-" + player.getEntityId();
while (name.length() > 16) {
name = name.substring(16);
}
info.setData(List.of(new PlayerInfoData(new WrappedGameProfile(uuid, player.getName()), 0, EnumWrappers.NativeGameMode.CREATIVE, WrappedChatComponent.fromText(name))));
for (final Player p : sendTo) sendPacket(p, info.getHandle());
return;
}
PacketContainer packet = new PacketContainer(PacketType.Play.Server.PLAYER_INFO_REMOVE);
packet.getUUIDLists().write(0, List.of(uuid));
for (final Player p : sendTo) sendPacket(p, packet);

View File

@@ -6,7 +6,7 @@ config-version: 1
default-menu: defaultmenu
debug-mode: false
database-settings:
type: sqlite #MYSQL, SQLite
type: sqlite # SQLite (Default), MYSQL, NONE
mysql:
database: database
password: cherryBomb
@@ -45,19 +45,41 @@ cosmetic-settings:
emote-camera: true
# If a player should be able to move in an emote. This option really only affects if "emote-camera" is false
emote-move: false
# This make it so it always sends the riding packets for the backpack. This sends more packets but is more reliable for servers which modify player passengers.
backpack-force-riding-packet: false
# This makes the plugin either (true) always have the backpack eminate light to avoid the black backpack bug or (false) turns it off.
backpack-light-emination: true
# This activates the block detection for the backpack. This allows backpacks to not appear completely black when in a block.
# Requires backpack-light-emination to be true.
backpack-block-detection: true
# This helps reduce the amount of packets sent for packet entities, but reduces accuracy of the entity. This is in milliseconds. -1 to disable.
# This is useful for servers with a lot of backpacks, as they are passengers, which means the client will update their position automatically within an area where the entity is located.
entity-cooldown-teleport-packet: 500
# This forces the offhand to always show the cosmetic. False means it will only show when the slot is empty.
# There is a small visual blip for a tick when you put a new item in the offhand slot, hence why its disabled by default.
offhand-always-show: false
helmet-add-enchantments: false # If the plugin should keep enchants on helmets. This is useful as some enchantments are client side only.
chest-add-enchantments: false # If the plugin should keep enchants on chestplate. This is useful as some enchantments are client side only.
leggings-add-enchantments: false # If the plugin should keep enchants on leggings. This is useful as some enchantments are client side only.
boots-add-enchantments: false # If the plugin should keep enchants on boots. This is useful as some enchantments are client side only.
slot-options:
helmet:
# If the plugin should keep enchants on helmets. This is useful as some enchantments are client side only.
add-enchantments: false
# Should the player slot be empty for the cosmetic to be applied? A cosmetic will be "hidden" if a player has an item equipped in the slot
require-empty: false
chestplate:
add-enchantments: false
require-empty: false
leggings:
add-enchantments: false
require-empty: false
boots:
add-enchantments: false
require-empty: false
offhand:
add-enchantments: false
# There is a small visual blip for a tick when you put a new item in the offhand slot, hence why its enabled by default.
require-empty: true
# This attempts to destroy cosmetics that get loose in the wild, such as through a player entering creative mode.
# Most servers who don't use creative mode and have properly set up the plugin should have no need for this and can leave it disabled.
@@ -67,12 +89,20 @@ cosmetic-settings:
# setting this to lower than the server player view distance should fix the
# bug where players see random backpacks. Put -1 to ignore and send packets to everyone.
view-distance: 32
# If the plugin should set the pitch of balloons to always be 0, to prevent players looking up affecting the balloon.
# This only applies to models that have a "head" section to them. THIS DOES NOT IMPACT THE REST OF THE ENTITY.
balloon-head-unmoving: false
# how the balloon should be positioned relative to the player
balloon-offset:
x: 0.5
y: 3
z: 0.5
menu-settings:
click-cooldown:
enabled: true
# This is the cooldown in miliseconds for the menu. This is useful for servers that have a lot of players.
# (So if a user clicks the menu, it won't spam the server with requesting it to refresh itself)
time: 1000
shading:
# Below is the shading mechanism behind cosmetic items. This is a bit complicated, but it allows for a lot of customization.
# The shading is done through the title and by shifting textures around. This is done by offsets.
@@ -92,11 +122,11 @@ menu-settings:
equip-click: "ANY" # ANY or ClickType, https://jd.papermc.io/paper/1.20/org/bukkit/event/inventory/ClickType.html
unequip-click: "ANY" # ANY or ClickType, https://jd.papermc.io/paper/1.20/org/bukkit/event/inventory/ClickType.html
dye-menu:
# If you use ItemsAdder, set this to "§f:offset_-8::dye_menu:"
# If you use Oraxen, set this to "<glyph:neg_shift_8><glyph:dye_menu>"
title: "§f"
input-slot: 19
output-slot: 25
# If you use ItemsAdder, set this to "<white>:img_offset_-8::img_dye_menu:"
# If you use Oraxen, set this to "<white><s:-8><g:dye_menu>"
title: "<white>"
input-slot: 10
output-slot: 16
hook-settings:
itemsadder:
# This causes the plugin to reload itself after any ItemsAdder change. This keeps the plugin fully up to date with IA, but
@@ -115,6 +145,10 @@ wardrobe:
return-last-location: false
# If players in wardrobes should be able to equip any cosmetic, regardless of permission (Cosmetics they do not have access to will be removed when they leave the wardrobe)
unchecked-wardrobe-cosmetics: false
# If HMCC should prevent a player from being damaged while being in the wardrobe
prevent-damage: true
# If a player is damaged in a wardrobe, and if it's set to true, it'll kick them from the wardrobe (prevent-damage must be false)
damage-kicked: false
menu-options:
enter-open-menu: false # If the menu should open when a player enters a wardrobe

View File

@@ -134,33 +134,34 @@ items:
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_kite%"
type: cosmetic
cosmetic: kite
handstand:
slots:
- 12
item:
material: PAPER
name: "<blue>Handstand Emote"
type: cosmetic
cosmetic: handstand
meditate:
slots:
- 13
item:
material: PAPER
name: "<blue>Meditate Emote"
type: cosmetic
cosmetic: meditate
thinking:
slots:
- 14
item:
material: PAPER
name: "<blue>Thinking Emote"
type: cosmetic
cosmetic: thinking
# EMOTES DO NOT WORK IN RECENT HMCCOSMETICS VERSIONS.
# handstand:
# slots:
# - 12
# item:
# material: PAPER
# name: "<blue>Handstand Emote"
# type: cosmetic
# cosmetic: handstand
# meditate:
# slots:
# - 13
# item:
# material: PAPER
# name: "<blue>Meditate Emote"
# type: cosmetic
# cosmetic: meditate
# thinking:
# slots:
# - 14
# item:
# material: PAPER
# name: "<blue>Thinking Emote"
# type: cosmetic
# cosmetic: thinking
explorer_backpack:
slots:
- 15
- 12
item:
material: hmccosmetics:explorer_backpack
lore:
@@ -171,7 +172,7 @@ items:
cosmetic: explorer_backpack
garbage_truck_balloon:
slots:
- 16
- 13
item:
material: hmccosmetics:garbage_truck_balloon
lore:
@@ -182,7 +183,7 @@ items:
cosmetic: garbage_truck_balloon
earth_day_grabber:
slots:
- 17
- 14
item:
material: hmccosmetics:earth_day_grabber
lore:
@@ -193,7 +194,7 @@ items:
cosmetic: earth_day_grabber
hibiscus_flower:
slots:
- 18
- 15
item:
material: hmccosmetics:hibiscus_flower
lore:

View File

@@ -9,6 +9,7 @@ not-enough-args: "%prefix% <red>Improper amount of arguments"
no-permission: "%prefix% <red>No Permission!"
no-cosmetic-permission: "%prefix% <red>You do not have permission for this cosmetic!"
no-cosmetic-slot: "%prefix% <red>There are no cosmetics in that slot!"
on-click-cooldown: "%prefix% <red>You are on cooldown!"
opened-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9>Opened wardrobe!"
closed-wardrobe: "%prefix% <gradient:#6D9DC5:#45CDE9>Closed wardrobe!"

View File

@@ -13,6 +13,9 @@ in-wardrobe:
using-cosmetic:
true: "true"
false: "false"
hidden:
true: "true"
false: "false"
current-cosmetic:
no-cosmetic: "No Cosmetic"
none: "none"