9
0
mirror of https://github.com/HibiscusMC/HMCCosmetics.git synced 2025-12-21 16:09:27 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Boy0000
684e02f768 drop protocollib 2025-05-22 22:10:31 +02:00
54 changed files with 974 additions and 1679 deletions

View File

@@ -8,7 +8,7 @@ plugins {
} }
group = "com.hibiscusmc" group = "com.hibiscusmc"
version = "2.8.2${getGitCommitHash()}" version = "2.7.8${getGitCommitHash()}"
allprojects { allprojects {
apply(plugin = "java") apply(plugin = "java")
@@ -16,7 +16,6 @@ allprojects {
repositories { repositories {
mavenCentral() mavenCentral()
mavenLocal()
// Paper Repo // Paper Repo
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
@@ -25,7 +24,8 @@ allprojects {
// Jitpack // Jitpack
maven("https://jitpack.io") maven("https://jitpack.io")
// Geary // ProtocolLib repo
maven("https://repo.dmulloy2.net/repository/public/") //ProtocolLib Repo, constantly down
maven("https://repo.mineinabyss.com/releases/") maven("https://repo.mineinabyss.com/releases/")
maven("https://repo.mineinabyss.com/snapshots/") maven("https://repo.mineinabyss.com/snapshots/")
@@ -69,13 +69,14 @@ allprojects {
// Hibiscus Commons // Hibiscus Commons
maven("https://repo.hibiscusmc.com/releases") maven("https://repo.hibiscusmc.com/releases")
mavenLocal()
} }
dependencies { dependencies {
compileOnly(fileTree("${project.rootDir}/lib") { include("*.jar") }) compileOnly(fileTree("${project.rootDir}/lib") { include("*.jar") })
compileOnly("com.mojang:authlib:1.5.25") compileOnly("com.mojang:authlib:1.5.25")
//compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT") //compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
compileOnly("org.jetbrains:annotations:24.1.0") compileOnly("org.jetbrains:annotations:24.1.0")
compileOnly("me.clip:placeholderapi:2.11.6") compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.6") compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.6")
@@ -85,21 +86,18 @@ allprojects {
exclude(group = "com.google.code.gson") exclude(group = "com.google.code.gson")
exclude(group = "it.unimi.dsi") exclude(group = "it.unimi.dsi")
exclude(group = "com.sk89q.jnbt") exclude(group = "com.sk89q.jnbt")
exclude(group = "org.enginehub.lin-bus.format")
} }
compileOnly("io.github.toxicity188:BetterHud-standard-api:1.12") //Standard api compileOnly("io.github.toxicity188:BetterHud-standard-api:1.12") //Standard api
compileOnly("io.github.toxicity188:BetterHud-bukkit-api:1.12") //Platform api compileOnly("io.github.toxicity188:BetterHud-bukkit-api:1.12") //Platform api
compileOnly("io.github.toxicity188:BetterCommand:1.3") //BetterCommand library compileOnly("io.github.toxicity188:BetterCommand:1.3") //BetterCommand library
//compileOnly("it.unimi.dsi:fastutil:8.5.14") //compileOnly("it.unimi.dsi:fastutil:8.5.14")
compileOnly("org.projectlombok:lombok:1.18.34") compileOnly("org.projectlombok:lombok:1.18.34")
compileOnly("me.lojosho:HibiscusCommons:0.8.1-d9fbae1d") compileOnly("me.lojosho:HibiscusCommons:0.6.3-32402bd")
// Handled by Spigot Library Loader ~ Deprecated as of Dec 16, 2025 // Handled by Spigot Library Loader
/* compileOnly("net.kyori:adventure-api:4.19.0")
compileOnly("net.kyori:adventure-api:4.24.0") compileOnly("net.kyori:adventure-text-minimessage:4.19.0")
compileOnly("net.kyori:adventure-text-minimessage:4.24.0") compileOnly("net.kyori:adventure-platform-bukkit:4.3.4")
compileOnly("net.kyori:adventure-platform-bukkit:4.4.1")
*/
annotationProcessor("org.projectlombok:lombok:1.18.36") annotationProcessor("org.projectlombok:lombok:1.18.36")
testCompileOnly("org.projectlombok:lombok:1.18.36") testCompileOnly("org.projectlombok:lombok:1.18.36")
@@ -109,6 +107,7 @@ allprojects {
exclude("net.kyori") // Already have adventure API exclude("net.kyori") // Already have adventure API
} }
implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT") implementation("com.owen1212055:particlehelper:1.0.0-SNAPSHOT")
implementation("com.ticxo.playeranimator:PlayerAnimator:R1.2.7")
} }
tasks { tasks {
@@ -141,14 +140,12 @@ tasks {
} }
runServer { runServer {
minecraftVersion("1.21.8") minecraftVersion("1.21.4")
downloadPlugins { downloadPlugins {
hangar("PlaceholderAPI", "2.11.6") hangar("PlaceholderAPI", "2.11.6")
hangar("Multiverse-Core", "5.3.4") url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar")
url("https://download.luckperms.net/1604/bukkit/loader/LuckPerms-Bukkit-5.5.15.jar") url("https://download.luckperms.net/1567/bukkit/loader/LuckPerms-Bukkit-5.4.150.jar")
github("Test-Account666", "PlugManX", "2.4.1", "PlugManX-2.4.1.jar")
//github("gecolay", "GSit", "2.4.3", "GSit-2.4.3.jar")
} }
} }
@@ -185,7 +182,7 @@ bukkit {
apiVersion = "1.20" apiVersion = "1.20"
authors = listOf("LoJoSho") authors = listOf("LoJoSho")
depend = listOf("HibiscusCommons") depend = listOf("HibiscusCommons")
softDepend = listOf("Nexo", "BetterHud", "ModelEngine", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen", "MMOItems", "Eco") softDepend = listOf("BetterHud", "ModelEngine", "Nexo", "Oraxen", "ItemsAdder", "Geary", "HMCColor", "WorldGuard", "MythicMobs", "PlaceholderAPI", "SuperVanish", "PremiumVanish", "LibsDisguises", "Denizen", "MMOItems", "Eco")
version = "${project.version}" version = "${project.version}"
loadBefore = listOf( loadBefore = listOf(
"Cosmin" // Fixes an issue with Cosmin loading before and taking /cosmetic, when messing with what we do. "Cosmin" // Fixes an issue with Cosmin loading before and taking /cosmetic, when messing with what we do.

View File

@@ -1,6 +1,11 @@
plugins { plugins {
id("java") id("java")
id("maven-publish") id("maven-publish")
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
}
dependencies {
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
} }
java { java {

View File

@@ -11,26 +11,23 @@ import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.database.Database; import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.gui.Menu; import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.gui.special.impl.HMCColorDyeMenu;
import com.hibiscusmc.hmccosmetics.hooks.items.HookHMCCosmetics; import com.hibiscusmc.hmccosmetics.hooks.items.HookHMCCosmetics;
import com.hibiscusmc.hmccosmetics.hooks.misc.HookBetterHud; import com.hibiscusmc.hmccosmetics.hooks.misc.HookBetterHud;
import com.hibiscusmc.hmccosmetics.hooks.placeholders.HMCPlaceholderExpansion; import com.hibiscusmc.hmccosmetics.hooks.placeholders.HMCPlaceholderExpansion;
import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGHook; import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGHook;
import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGListener; import com.hibiscusmc.hmccosmetics.hooks.worldguard.WGListener;
import com.hibiscusmc.hmccosmetics.listener.*; import com.hibiscusmc.hmccosmetics.listener.PaperPlayerGameListener;
import com.hibiscusmc.hmccosmetics.packets.CosmeticPacketInterface; import com.hibiscusmc.hmccosmetics.listener.PlayerConnectionListener;
import com.hibiscusmc.hmccosmetics.listener.PlayerGameListener;
import com.hibiscusmc.hmccosmetics.listener.ServerListener;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.PlayerSearchManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.TranslationUtil; import com.hibiscusmc.hmccosmetics.util.TranslationUtil;
import lombok.Getter;
import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin;
import me.lojosho.hibiscuscommons.HibiscusPlugin; import me.lojosho.hibiscuscommons.HibiscusPlugin;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer; import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.hibiscuscommons.config.serializer.LocationSerializer; import me.lojosho.hibiscuscommons.config.serializer.LocationSerializer;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.shaded.configupdater.common.config.CommentedConfiguration; import me.lojosho.shaded.configupdater.common.config.CommentedConfiguration;
import me.lojosho.shaded.configurate.ConfigurateException; import me.lojosho.shaded.configurate.ConfigurateException;
import me.lojosho.shaded.configurate.ConfigurationOptions; import me.lojosho.shaded.configurate.ConfigurationOptions;
@@ -50,9 +47,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
private static HMCCosmeticsPlugin instance; private static HMCCosmeticsPlugin instance;
private static YamlConfigurationLoader configLoader; private static YamlConfigurationLoader configLoader;
@Getter
private PlayerSearchManager playerSearchManager;
public HMCCosmeticsPlugin() { public HMCCosmeticsPlugin() {
super(13873, 1879); super(13873, 1879);
new HookHMCCosmetics(); new HookHMCCosmetics();
@@ -64,20 +58,12 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
// Plugin startup logic // Plugin startup logic
instance = this; instance = this;
// Search Service
this.playerSearchManager = new PlayerSearchManager(this);
// File setup // File setup
saveDefaultConfig(); saveDefaultConfig();
if (!Path.of(getDataFolder().getPath(), "messages.yml").toFile().exists()) saveResource("messages.yml", false); if (!Path.of(getDataFolder().getPath(), "messages.yml").toFile().exists()) saveResource("messages.yml", false);
if (!Path.of(getDataFolder().getPath(), "translations.yml").toFile().exists()) saveResource("translations.yml", false); if (!Path.of(getDataFolder().getPath(), "translations.yml").toFile().exists()) saveResource("translations.yml", false);
if (!Path.of(getDataFolder().getPath() + "/cosmetics/").toFile().exists()) saveResource("cosmetics/defaultcosmetics.yml", false); if (!Path.of(getDataFolder().getPath() + "/cosmetics/").toFile().exists()) saveResource("cosmetics/defaultcosmetics.yml", false);
if (!Path.of(getDataFolder().getPath() + "/menus/").toFile().exists()) { if (!Path.of(getDataFolder().getPath() + "/menus/").toFile().exists()) saveResource("menus/defaultmenu.yml", false);
saveResource("menus/defaultmenu_hats.yml", false);
saveResource("menus/defaultmenu_balloons.yml", false);
saveResource("menus/defaultmenu_hands.yml", false);
saveResource("menus/defaultmenu_backpacks.yml", false);
}
// Configuration Sync // Configuration Sync
final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile(); final File configFile = Path.of(getInstance().getDataFolder().getPath(), "config.yml").toFile();
@@ -97,7 +83,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
// Setup // Setup
setup(); setup();
setPacketInterface(new CosmeticPacketInterface());
// Commands // Commands
getServer().getPluginCommand("cosmetic").setExecutor(new CosmeticCommand()); getServer().getPluginCommand("cosmetic").setExecutor(new CosmeticCommand());
@@ -107,8 +92,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
getServer().getPluginManager().registerEvents(new PlayerConnectionListener(), this); getServer().getPluginManager().registerEvents(new PlayerConnectionListener(), this);
getServer().getPluginManager().registerEvents(new PlayerGameListener(), this); getServer().getPluginManager().registerEvents(new PlayerGameListener(), this);
getServer().getPluginManager().registerEvents(new ServerListener(), this); getServer().getPluginManager().registerEvents(new ServerListener(), this);
getServer().getPluginManager().registerEvents(new PlayerMovementListener(), this);
getServer().getPluginManager().registerEvents(playerSearchManager, this);
if (HibiscusCommonsPlugin.isOnPaper()) { if (HibiscusCommonsPlugin.isOnPaper()) {
getServer().getPluginManager().registerEvents(new PaperPlayerGameListener(), this); getServer().getPluginManager().registerEvents(new PaperPlayerGameListener(), this);
@@ -120,15 +103,6 @@ public final class HMCCosmeticsPlugin extends HibiscusPlugin {
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null && Settings.isWorldGuardMoveCheck()) { if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null && Settings.isWorldGuardMoveCheck()) {
getServer().getPluginManager().registerEvents(new WGListener(), this); getServer().getPluginManager().registerEvents(new WGListener(), this);
} }
// HMCColor
if (Hooks.isActiveHook("HMCColor")) {
try {
DyeMenuProvider.setDyeMenuProvider(new HMCColorDyeMenu());
} catch (IllegalStateException e) {
getLogger().warning("Unable to set HMCColor as the dye menu. There is likely another plugin registering another dye menu.");
}
}
} }
@Override @Override

View File

@@ -12,6 +12,7 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUserProvider;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import me.lojosho.hibiscuscommons.nms.MinecraftVersion; import me.lojosho.hibiscuscommons.nms.MinecraftVersion;
import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -20,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer;
/** /**
* The main API class for HMCCosmetics. This class provides methods to interact with the plugin. * The main API class for HMCCosmetics. This class provides methods to interact with the plugin.

View File

@@ -1,6 +1,7 @@
package com.hibiscusmc.hmccosmetics.api.events; package com.hibiscusmc.hmccosmetics.api.events;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**

View File

@@ -14,7 +14,6 @@ import com.hibiscusmc.hmccosmetics.database.Database;
import com.hibiscusmc.hmccosmetics.gui.Menu; import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu; import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -310,17 +309,13 @@ public class CosmeticCommand implements CommandExecutor {
return true; return true;
} }
final String rawSlot = args[1]; String rawSlot = args[1];
if (!CosmeticSlot.contains(rawSlot)) { if (!CosmeticSlot.contains(rawSlot)) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-slot"); if (!silent) MessagesUtil.sendMessage(player, "invalid-slot");
return true; return true;
} }
final CosmeticSlot slot = CosmeticSlot.valueOf(rawSlot); // This is checked above. While IDEs may say the slot might be null, it will not be. CosmeticSlot slot = CosmeticSlot.valueOf(rawSlot);
final Cosmetic cosmetic = user.getCosmetic(slot); Cosmetic cosmetic = user.getCosmetic(slot);
if (cosmetic == null) {
if (!silent) MessagesUtil.sendMessage(player, "invalid-slot");
return true;
}
if (args.length >= 3) { if (args.length >= 3) {
if (args[2].isEmpty()) { if (args[2].isEmpty()) {
@@ -334,11 +329,7 @@ public class CosmeticCommand implements CommandExecutor {
} }
user.addCosmetic(cosmetic, color); // #FFFFFF user.addCosmetic(cosmetic, color); // #FFFFFF
} else { } else {
if (DyeMenuProvider.hasMenuProvider()) { DyeMenu.openMenu(user, cosmetic);
DyeMenuProvider.openMenu(player, user, cosmetic);
} else {
if (!silent) MessagesUtil.sendMessage(player, "invalid-color");
}
} }
} }
case ("setwardrobesetting") -> { case ("setwardrobesetting") -> {
@@ -409,7 +400,6 @@ public class CosmeticCommand implements CommandExecutor {
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) { if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) {
player.sendMessage("Backpack Location -> " + user.getUserBackpackManager().getEntityManager().getLocation()); player.sendMessage("Backpack Location -> " + user.getUserBackpackManager().getEntityManager().getLocation());
} }
player.sendMessage("Cosmetic Passengers -> " + user.getUserBackpackManager().getAreaEffectEntityId());
player.sendMessage("Cosmetics -> " + user.getCosmetics()); player.sendMessage("Cosmetics -> " + user.getCosmetics());
player.sendMessage("EntityId -> " + player.getEntityId()); player.sendMessage("EntityId -> " + player.getEntityId());
return true; return true;

View File

@@ -43,10 +43,10 @@ public class Settings {
private static final String HOOK_WG_MOVE_CHECK_PATH = "player-move-check"; private static final String HOOK_WG_MOVE_CHECK_PATH = "player-move-check";
private static final String HOOK_WG_MOVE_CHECK_PATH_LEGACY = "player_move_check"; private static final String HOOK_WG_MOVE_CHECK_PATH_LEGACY = "player_move_check";
private static final String COSMETIC_DISABLED_WORLDS_PATH = "disabled-worlds"; 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_BACKPACK_FORCE_RIDING_PACKET_PATH = "backpack-force-riding-packet";
private static final String COSMETIC_DESTROY_LOOSE_COSMETIC_PATH = "destroy-loose-cosmetics"; 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 COSMETIC_BALLOON_HEAD_FORWARD_PATH = "balloon-head-forward";
private static final String COSMETIC_OFFHAND_PREVENT_SWAPPING = "offhand-prevent-swapping";
private static final String MENU_SETTINGS_PATH = "menu-settings"; 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_PATH = "click-cooldown";
private static final String MENU_CLICK_COOLDOWN_TIME_PATH = "time"; private static final String MENU_CLICK_COOLDOWN_TIME_PATH = "time";
@@ -101,8 +101,6 @@ public class Settings {
@Getter @Getter
private static boolean destroyLooseCosmetics; private static boolean destroyLooseCosmetics;
@Getter @Getter
private static boolean preventOffhandSwapping;
@Getter
private static boolean backpackForceRidingEnabled; private static boolean backpackForceRidingEnabled;
@Getter @Getter
private static boolean disabledGamemodesEnabled; private static boolean disabledGamemodesEnabled;
@@ -119,10 +117,14 @@ public class Settings {
@Getter @Getter
private static int tickPeriod; private static int tickPeriod;
@Getter @Getter
private static int packetEntityTeleportCooldown;
@Getter
private static Long defaultMenuCooldown; private static Long defaultMenuCooldown;
@Getter @Getter
private static boolean menuClickCooldown; private static boolean menuClickCooldown;
@Getter @Getter
private static double emoteDistance;
@Getter
private static Vector balloonOffset; private static Vector balloonOffset;
@Getter @Getter
private static String cosmeticEquipClickType; private static String cosmeticEquipClickType;
@@ -190,7 +192,6 @@ public class Settings {
forceShowOnJoin = cosmeticSettings.node(FORCE_SHOW_COSMETICS_PATH).getBoolean(false); forceShowOnJoin = cosmeticSettings.node(FORCE_SHOW_COSMETICS_PATH).getBoolean(false);
destroyLooseCosmetics = cosmeticSettings.node(COSMETIC_DESTROY_LOOSE_COSMETIC_PATH).getBoolean(false); destroyLooseCosmetics = cosmeticSettings.node(COSMETIC_DESTROY_LOOSE_COSMETIC_PATH).getBoolean(false);
backpackForceRidingEnabled = cosmeticSettings.node(COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH).getBoolean(false); backpackForceRidingEnabled = cosmeticSettings.node(COSMETIC_BACKPACK_FORCE_RIDING_PACKET_PATH).getBoolean(false);
preventOffhandSwapping = cosmeticSettings.node(COSMETIC_OFFHAND_PREVENT_SWAPPING).getBoolean(false);
cosmeticSettings.node(SLOT_OPTIONS_PATH).childrenMap().forEach((key, value) -> { cosmeticSettings.node(SLOT_OPTIONS_PATH).childrenMap().forEach((key, value) -> {
EquipmentSlot slot = convertConfigToEquipment(key.toString().toLowerCase()); EquipmentSlot slot = convertConfigToEquipment(key.toString().toLowerCase());
@@ -205,6 +206,7 @@ public class Settings {
tickPeriod = cosmeticSettings.node(TICK_PERIOD_PATH).getInt(-1); tickPeriod = cosmeticSettings.node(TICK_PERIOD_PATH).getInt(-1);
viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt(-3); viewDistance = cosmeticSettings.node(VIEW_DISTANCE_PATH).getInt(-3);
packetEntityTeleportCooldown = cosmeticSettings.node(COSMETIC_PACKET_ENTITY_TELEPORT_COOLDOWN_PATH).getInt(-1);
balloonHeadForward = cosmeticSettings.node(COSMETIC_BALLOON_HEAD_FORWARD_PATH).getBoolean(false); balloonHeadForward = cosmeticSettings.node(COSMETIC_BALLOON_HEAD_FORWARD_PATH).getBoolean(false);
backpackPreventDarkness = cosmeticSettings.node(BACKPACK_PREVENT_DARKNESS_PATH).getBoolean(true); backpackPreventDarkness = cosmeticSettings.node(BACKPACK_PREVENT_DARKNESS_PATH).getBoolean(true);
@@ -226,9 +228,9 @@ public class Settings {
lockedCosmeticColor = shadingSettings.node(LOCKED_COSMETIC_COLOR_PATH).getString(); lockedCosmeticColor = shadingSettings.node(LOCKED_COSMETIC_COLOR_PATH).getString();
ConfigurationNode cosmeticTypeSettings = menuSettings.node(COSMETIC_TYPE_SETTINGS_PATH); ConfigurationNode cosmeticTypeSettings = menuSettings.node(COSMETIC_TYPE_SETTINGS_PATH);
cosmeticEquipClickType = cosmeticTypeSettings.node(EQUIP_CLICK_TYPE).getString("ANY"); cosmeticEquipClickType = cosmeticTypeSettings.node(EQUIP_CLICK_TYPE).getString("ALL");
cosmeticUnEquipClickType = cosmeticTypeSettings.node(UNEQUIP_CLICK_TYPE).getString("ANY"); cosmeticUnEquipClickType = cosmeticTypeSettings.node(UNEQUIP_CLICK_TYPE).getString("ALL");
cosmeticDyeClickType = cosmeticTypeSettings.node(DYE_CLICK_TYPE).getString("ANY"); cosmeticDyeClickType = cosmeticTypeSettings.node(DYE_CLICK_TYPE).getString("ALL");
final var balloonSection = cosmeticSettings.node(BALLOON_OFFSET); final var balloonSection = cosmeticSettings.node(BALLOON_OFFSET);
balloonOffset = loadVector(balloonSection); balloonOffset = loadVector(balloonSection);

View File

@@ -1,19 +1,18 @@
package com.hibiscusmc.hmccosmetics.cosmetic; package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer; import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException; import me.lojosho.shaded.configurate.serialize.SerializationException;
import org.bukkit.ChatColor; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -27,16 +26,13 @@ public abstract class Cosmetic {
static { static {
UNDEFINED_DISPLAY_ITEM_STACK = new ItemStack(Material.BARRIER); UNDEFINED_DISPLAY_ITEM_STACK = new ItemStack(Material.BARRIER);
UNDEFINED_DISPLAY_ITEM_STACK.editMeta(meta -> {
ItemMeta meta = UNDEFINED_DISPLAY_ITEM_STACK.getItemMeta(); meta.displayName(Component.text("Undefined Item Display", NamedTextColor.RED));
if (meta != null) { meta.lore(List.of(
// Legacy methods for Spigot >:( Component.text("Please check your configurations & console to", NamedTextColor.RED),
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&cUndefined Item Display")); Component.text("ensure there are no errors.", NamedTextColor.RED)
meta.setLore(List.of( ));
ChatColor.translateAlternateColorCodes('&', "&cPlease check your configurations & console to"), });
ChatColor.translateAlternateColorCodes('&', "&censure there are no errors.")));
}
UNDEFINED_DISPLAY_ITEM_STACK.setItemMeta(meta);
} }
/** Identifier of the cosmetic. */ /** Identifier of the cosmetic. */
@@ -58,12 +54,8 @@ public abstract class Cosmetic {
/** Whether the cosmetic is dyeable or not. */ /** Whether the cosmetic is dyeable or not. */
private boolean dyeable; private boolean dyeable;
/** The config for the cosmetic */
private ConfigurationNode config;
protected Cosmetic(@NotNull String id, @NotNull ConfigurationNode config) { protected Cosmetic(@NotNull String id, @NotNull ConfigurationNode config) {
this.id = id; this.id = id;
this.config = config;
if (!config.node("permission").virtual()) { if (!config.node("permission").virtual()) {
this.permission = config.node("permission").getString(); this.permission = config.node("permission").getString();
@@ -102,24 +94,19 @@ public abstract class Cosmetic {
} }
/** /**
* Dispatched when an update is requested upon the cosmetic. Instead, you should use {@link CosmeticUser#updateCosmetic(CosmeticSlot)})} * Dispatched when an update is requested upon the cosmetic.
* @param user the user to preform the update against * @param user the user to preform the update against
*/ */
@Deprecated(since = "2.8.2") public final void update(CosmeticUser user) {
public void update(CosmeticUser user) { this.doUpdate(user);
if(this instanceof CosmeticUpdateBehavior behavior) {
behavior.dispatchUpdate(user);
}
} }
/** /**
* Action preformed on the update. Instead, you should use {@link CosmeticUser#updateCosmetic(CosmeticSlot)})} * Action preformed on the update.
* @param user the user to preform the update against * @param user the user to preform the update against
*/ */
@Deprecated(since = "2.8.2")
protected void doUpdate(final CosmeticUser user) { protected void doUpdate(final CosmeticUser user) {
// #update should be the preferred way of interacting with this api now. // NO-OP.
this.update(user);
} }
@Nullable @Nullable
@@ -146,14 +133,4 @@ public abstract class Cosmetic {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* While cosmetics registered in HMCC are made through a configuration, cosmetics registered from other plugins
* may not and instead opt for {@link Cosmetic#Cosmetic(String, String, ItemStack, String, CosmeticSlot, boolean)}, which doesn't use a config.
* This should be used only for reference.
*/
@ApiStatus.Experimental
public @Nullable ConfigurationNode getConfig() {
return config;
}
} }

View File

@@ -3,7 +3,6 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableCollection;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -55,9 +54,7 @@ public interface CosmeticHolder {
boolean canEquipCosmetic(@NotNull Cosmetic cosmetic, boolean ignoreWardrobe); boolean canEquipCosmetic(@NotNull Cosmetic cosmetic, boolean ignoreWardrobe);
boolean updateCosmetic(@NotNull CosmeticSlot slot); void updateCosmetic(@NotNull CosmeticSlot slot);
boolean updateMovementCosmetic(@NotNull CosmeticSlot slot, final Location from, final Location to);
/** /**
* Just for backwards compatibility, ensures that the given viewer and the given cosmetic holder * Just for backwards compatibility, ensures that the given viewer and the given cosmetic holder

View File

@@ -2,10 +2,12 @@ package com.hibiscusmc.hmccosmetics.cosmetic;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.cosmetic.types.*; import com.hibiscusmc.hmccosmetics.cosmetic.types.*;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@@ -22,6 +24,8 @@ public abstract class CosmeticProvider {
Map.entry(CosmeticSlot.BOOTS, CosmeticArmorType::new), Map.entry(CosmeticSlot.BOOTS, CosmeticArmorType::new),
Map.entry(CosmeticSlot.OFFHAND, CosmeticArmorType::new), Map.entry(CosmeticSlot.OFFHAND, CosmeticArmorType::new),
Map.entry(CosmeticSlot.MAINHAND, CosmeticMainhandType::new),
Map.entry(CosmeticSlot.BACKPACK, CosmeticBackpackType::new), Map.entry(CosmeticSlot.BACKPACK, CosmeticBackpackType::new),
Map.entry(CosmeticSlot.BALLOON, CosmeticBalloonType::new) Map.entry(CosmeticSlot.BALLOON, CosmeticBalloonType::new)

View File

@@ -1,16 +0,0 @@
package com.hibiscusmc.hmccosmetics.cosmetic.behavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
/**
* Updates cosmetics whenever a player moves.
*/
public interface CosmeticMovementBehavior {
void dispatchMove(
@NotNull final CosmeticUser user,
@NotNull final Location from,
@NotNull final Location to
);
}

View File

@@ -1,13 +0,0 @@
package com.hibiscusmc.hmccosmetics.cosmetic.behavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.jetbrains.annotations.NotNull;
/**
* Generic updates that happen every tick or when manually requested to be dispatched.
*/
public interface CosmeticUpdateBehavior {
void dispatchUpdate(
@NotNull final CosmeticUser user
);
}

View File

@@ -2,7 +2,6 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils; import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
@@ -16,7 +15,8 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CosmeticArmorType extends Cosmetic implements CosmeticUpdateBehavior { public class CosmeticArmorType extends Cosmetic {
private final EquipmentSlot equipSlot; private final EquipmentSlot equipSlot;
public CosmeticArmorType(String id, ConfigurationNode config) { public CosmeticArmorType(String id, ConfigurationNode config) {
@@ -31,7 +31,7 @@ public class CosmeticArmorType extends Cosmetic implements CosmeticUpdateBehavio
} }
@Override @Override
public void dispatchUpdate(@NotNull CosmeticUser user) { protected void doUpdate(@NotNull CosmeticUser user) {
if (user.isInWardrobe()) return; if (user.isInWardrobe()) return;
Entity entity = Bukkit.getEntity(user.getUniqueId()); Entity entity = Bukkit.getEntity(user.getUniqueId());
if (entity == null) return; if (entity == null) return;
@@ -48,11 +48,9 @@ public class CosmeticArmorType extends Cosmetic implements CosmeticUpdateBehavio
} }
public ItemStack getItem(@NotNull CosmeticUser user, ItemStack cosmeticItem) { public ItemStack getItem(@NotNull CosmeticUser user, ItemStack cosmeticItem) {
Player player = user.getPlayer(); if (!(user.getEntity() instanceof HumanEntity humanEntity)) return null;
if (player == null) return null;
if (Settings.getSlotOption(equipSlot).isAddEnchantments()) { if (Settings.getSlotOption(equipSlot).isAddEnchantments()) {
ItemStack equippedItem = player.getInventory().getItem(equipSlot); ItemStack equippedItem = humanEntity.getInventory().getItem(equipSlot);
cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments()); cosmeticItem.addUnsafeEnchantments(equippedItem.getEnchantments());
} }
// Basically, if force offhand is off AND there is no item in an offhand slot, then the equipment packet to add the cosmetic // Basically, if force offhand is off AND there is no item in an offhand slot, then the equipment packet to add the cosmetic

View File

@@ -2,19 +2,18 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticMovementBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager; import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
import com.hibiscusmc.hmccosmetics.user.manager.UserEntity; import com.hibiscusmc.hmccosmetics.user.manager.UserEntity;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -23,9 +22,11 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
public class CosmeticBackpackType extends Cosmetic {
@Getter @Getter
public class CosmeticBackpackType extends Cosmetic implements CosmeticUpdateBehavior, CosmeticMovementBehavior {
private int height = -1; private int height = -1;
private ItemStack firstPersonBackpack; private ItemStack firstPersonBackpack;
@@ -39,45 +40,37 @@ public class CosmeticBackpackType extends Cosmetic implements CosmeticUpdateBeha
} }
@Override @Override
public void dispatchUpdate(@NotNull CosmeticUser user) { protected void doUpdate(@NotNull CosmeticUser user) {
Entity entity = user.getEntity(); Entity entity = user.getEntity();
if(entity == null) { if (entity == null) return;
return;
}
Location entityLocation = entity.getLocation(); Location entityLocation = entity.getLocation();
Location loc = entityLocation.clone().add(0, 2, 0); Location loc = entityLocation.clone().add(0, 2, 0);
UserBackpackManager backpackManager = user.getUserBackpackManager(); if (user.isInWardrobe() || !user.isBackpackSpawned()) return;
if(backpackManager == null) return; if (user.isHidden()) {
// Sometimes the backpack is not despawned when the player is hidden (weird ass logic happening somewhere)
user.despawnBackpack();
return;
}
UserBackpackManager backpackManager = user.getUserBackpackManager();
UserEntity entityManager = backpackManager.getEntityManager(); UserEntity entityManager = backpackManager.getEntityManager();
if(entityManager == null) return; int firstArmorStandId = backpackManager.getFirstArmorStandId();
List<Player> outsideViewers = entityManager.refreshViewers(loc);
entityManager.teleport(loc); entityManager.teleport(loc);
entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible()); entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible());
int firstArmorStandId = backpackManager.getFirstArmorStandId(); HMCCPacketManager.sendEntitySpawnPacket(entityLocation, firstArmorStandId, EntityType.ARMOR_STAND, UUID.randomUUID(), outsideViewers);
HMCCPacketManager.sendArmorstandMetadata(firstArmorStandId, outsideViewers);
List<Player> newViewers = entityManager.refreshViewers(loc); PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), outsideViewers);
if(!newViewers.isEmpty()) {
HMCCPacketManager.spawnInvisibleArmorstand(firstArmorStandId, entityLocation, UUID.randomUUID(), newViewers);
PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, getItem()), newViewers);
if (user.getPlayer() != null) {
AttributeInstance scaleAttribute = user.getPlayer().getAttribute(Attribute.GENERIC_SCALE);
if (scaleAttribute != null) {
HMCCPacketManager.sendEntityScalePacket(user.getUserBackpackManager().getFirstArmorStandId(), scaleAttribute.getValue(), newViewers);
}
}
}
// If true, it will send the riding packet to all players. If false, it will send the riding packet only to new players // 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(), firstArmorStandId, entityManager.getViewers()); if (Settings.isBackpackForceRidingEnabled()) HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, entityManager.getViewers());
else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, newViewers); else HMCCPacketManager.sendRidingPacket(entity.getEntityId(), firstArmorStandId, outsideViewers);
if (isFirstPersonCompadible() && !user.isInWardrobe() && user.getPlayer() != null) { if (!user.isInWardrobe() && isFirstPersonCompadible() && user.getPlayer() != null) {
List<Player> owner = List.of(user.getPlayer()); List<Player> owner = List.of(user.getPlayer());
ArrayList<Integer> particleCloud = backpackManager.getAreaEffectEntityId(); ArrayList<Integer> particleCloud = backpackManager.getAreaEffectEntityId();
@@ -90,36 +83,21 @@ public class CosmeticBackpackType extends Cosmetic implements CosmeticUpdateBeha
} }
HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), firstArmorStandId, owner); HMCCPacketManager.sendRidingPacket(particleCloud.get(particleCloud.size() - 1), firstArmorStandId, owner);
if (!user.isHidden()) { if (!user.isHidden()) {
//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(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner); PacketManager.equipmentSlotUpdate(firstArmorStandId, EquipmentSlot.HEAD, user.getUserCosmeticItem(this, firstPersonBackpack), owner);
} }
//MessagesUtil.sendDebugMessages("First Person Backpack Update[owner=" + user.getUniqueId() + ",player_location=" + loc + "]!", Level.INFO);
} }
backpackManager.showBackpack(); backpackManager.showBackpack();
} }
@Override
public void dispatchMove(@NotNull CosmeticUser user, @NotNull Location from, @NotNull Location to) {
@SuppressWarnings("DuplicatedCode") // thanks.
Entity entity = user.getEntity();
if(entity == null) {
return;
}
Location entityLocation = entity.getLocation();
Location loc = entityLocation.clone().add(0, 2, 0);
UserBackpackManager backpackManager = user.getUserBackpackManager();
if(backpackManager == null) return;
UserEntity entityManager = backpackManager.getEntityManager();
if(entityManager == null) return;
entityManager.teleport(loc);
entityManager.setRotation((int) loc.getYaw(), isFirstPersonCompadible());
}
public boolean isFirstPersonCompadible() { public boolean isFirstPersonCompadible() {
return firstPersonBackpack != null; return firstPersonBackpack != null;
} }
public ItemStack getFirstPersonBackpack() {
return firstPersonBackpack;
}
} }

View File

@@ -2,8 +2,6 @@ package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticMovementBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager; import com.hibiscusmc.hmccosmetics.user.manager.UserBalloonManager;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -20,7 +18,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
public class CosmeticBalloonType extends Cosmetic implements CosmeticUpdateBehavior, CosmeticMovementBehavior { public class CosmeticBalloonType extends Cosmetic {
@Getter @Getter
private final String modelName; private final String modelName;
@@ -56,7 +54,7 @@ public class CosmeticBalloonType extends Cosmetic implements CosmeticUpdateBehav
} }
@Override @Override
public void dispatchUpdate(@NotNull CosmeticUser user) { protected void doUpdate(@NotNull CosmeticUser user) {
Entity entity = Bukkit.getEntity(user.getUniqueId()); Entity entity = Bukkit.getEntity(user.getUniqueId());
UserBalloonManager userBalloonManager = user.getBalloonManager(); UserBalloonManager userBalloonManager = user.getBalloonManager();
@@ -68,29 +66,6 @@ public class CosmeticBalloonType extends Cosmetic implements CosmeticUpdateBehav
return; return;
} }
Location newLocation = entity.getLocation();
newLocation = newLocation.clone().add(getBalloonOffset());
if (Settings.isBalloonHeadForward()) newLocation.setPitch(0);
if (!user.isHidden() && showLead) {
List<Player> sendTo = userBalloonManager.getPufferfish().refreshViewers(newLocation);
if (sendTo.isEmpty()) return;
user.getBalloonManager().getPufferfish().spawnPufferfish(newLocation, sendTo);
}
}
@Override
public void dispatchMove(@NotNull CosmeticUser user, @NotNull Location from, @NotNull Location to) {
Entity entity = Bukkit.getEntity(user.getUniqueId());
UserBalloonManager userBalloonManager = user.getBalloonManager();
if (entity == null || userBalloonManager == null) return;
if (user.isInWardrobe()) return;
if (!userBalloonManager.getModelEntity().isValid()) {
return;
}
Location newLocation = entity.getLocation(); Location newLocation = entity.getLocation();
Location currentLocation = user.getBalloonManager().getLocation(); Location currentLocation = user.getBalloonManager().getLocation();
newLocation = newLocation.clone().add(getBalloonOffset()); newLocation = newLocation.clone().add(getBalloonOffset());
@@ -115,6 +90,15 @@ public class CosmeticBalloonType extends Cosmetic implements CosmeticUpdateBehav
HMCCPacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer); HMCCPacketManager.sendTeleportPacket(userBalloonManager.getPufferfishBalloonId(), newLocation, false, viewer);
HMCCPacketManager.sendLeashPacket(userBalloonManager.getPufferfishBalloonId(), entity.getEntityId(), viewer); HMCCPacketManager.sendLeashPacket(userBalloonManager.getPufferfishBalloonId(), entity.getEntityId(), viewer);
if (user.isHidden()) {
userBalloonManager.getPufferfish().hidePufferfish();
return;
}
if (!user.isHidden() && showLead) {
List<Player> sendTo = userBalloonManager.getPufferfish().refreshViewers(newLocation);
if (sendTo.isEmpty()) return;
user.getBalloonManager().getPufferfish().spawnPufferfish(newLocation, sendTo);
}
} }
public boolean isDyeablePart(String name) { public boolean isDyeablePart(String name) {

View File

@@ -0,0 +1,23 @@
package com.hibiscusmc.hmccosmetics.cosmetic.types;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import me.lojosho.shaded.configurate.ConfigurationNode;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class CosmeticMainhandType extends Cosmetic {
public CosmeticMainhandType(String id, ConfigurationNode config) {
super(id, config);
}
@Override
protected void doUpdate(@NotNull CosmeticUser user) {
Player player = user.getPlayer();
HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), user, getSlot(), HMCCPacketManager.getViewers(player.getLocation()));
}
}

View File

@@ -1,5 +1,6 @@
package com.hibiscusmc.hmccosmetics.database.types; package com.hibiscusmc.hmccosmetics.database.types;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
@@ -8,6 +9,7 @@ import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.EnumUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color; import org.bukkit.Color;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -85,7 +87,7 @@ public abstract class Data {
private boolean shouldHiddenSave(CosmeticUser.HiddenReason reason) { private boolean shouldHiddenSave(CosmeticUser.HiddenReason reason) {
switch (reason) { switch (reason) {
case EMOTE, NONE, GAMEMODE, WORLD, DISABLED, POTION -> { case EMOTE, NONE, GAMEMODE, WORLD, DISABLED -> {
return false; return false;
} }
default -> { default -> {

View File

@@ -38,14 +38,12 @@ public class MySQLData extends SQLData {
HMCCosmeticsPlugin plugin = HMCCosmeticsPlugin.getInstance(); HMCCosmeticsPlugin plugin = HMCCosmeticsPlugin.getInstance();
try { try {
openConnection(); openConnection();
if (connection == null) throw new IllegalStateException("Connection is null"); if (connection == null) throw new NullPointerException("Connection is null");
try (PreparedStatement preparedStatement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " + connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
"(UUID varchar(36) PRIMARY KEY, " + "(UUID varchar(36) PRIMARY KEY, " +
"COSMETICS MEDIUMTEXT " + "COSMETICS MEDIUMTEXT " +
");")) { ");").execute();
preparedStatement.execute(); } catch (SQLException | NullPointerException e) {
}
} catch (SQLException | IllegalStateException e) {
plugin.getLogger().severe(""); plugin.getLogger().severe("");
plugin.getLogger().severe(""); plugin.getLogger().severe("");
plugin.getLogger().severe("MySQL DATABASE CAN NOT BE REACHED."); plugin.getLogger().severe("MySQL DATABASE CAN NOT BE REACHED.");
@@ -62,20 +60,32 @@ public class MySQLData extends SQLData {
@Override @Override
public void clear(UUID uniqueId) { public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> { Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try (PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;")) { PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt.setString(1, uniqueId.toString()); preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate(); preparedSt.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
} }
}); });
} }
private void openConnection() throws SQLException { private void openConnection() throws SQLException {
// Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
// ...
// });
// connection = DriverManager.getConnection("jdbc:mysql://" + DatabaseSettings.getHost() + ":" + DatabaseSettings.getPort() + "/" + DatabaseSettings.getDatabase(), setupProperties());
// Connection isn't null AND Connection isn't closed :: return // Connection isn't null AND Connection isn't closed :: return
try { try {
if (isConnectionOpen()) return; if (isConnectionOpen()) {
if (connection != null) close(); // Close connection if still active return;
} else if (connection != null) close(); // Close connection if still active
} catch (RuntimeException e) { } catch (RuntimeException e) {
e.printStackTrace(); // If isConnectionOpen() throws error e.printStackTrace(); // If isConnectionOpen() throws error
} }
@@ -84,15 +94,17 @@ public class MySQLData extends SQLData {
try { try {
Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database, setupProperties()); connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database, setupProperties());
} catch (SQLException | ClassNotFoundException e) { } catch (SQLException e) {
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} }
} }
public void close() { public void close() {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> { Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try { try {
if (connection == null) throw new IllegalStateException("Connection is null"); if (connection == null) throw new NullPointerException("Connection is null");
connection.close(); connection.close();
} catch (SQLException | NullPointerException e) { } catch (SQLException | NullPointerException e) {
System.out.println(e.getMessage()); System.out.println(e.getMessage());
@@ -103,12 +115,13 @@ public class MySQLData extends SQLData {
@NotNull @NotNull
private Properties setupProperties() { private Properties setupProperties() {
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("user", user); props.put("user", user);
props.setProperty("password", password); props.put("password", password);
props.put("autoReconnect", "true");
return props; return props;
} }
private boolean isConnectionOpen() { private boolean isConnectionOpen() throws RuntimeException {
try { try {
return connection != null && !connection.isClosed(); return connection != null && !connection.isClosed();
} catch (SQLException e) { } catch (SQLException e) {
@@ -130,9 +143,9 @@ public class MySQLData extends SQLData {
} }
try { try {
if (connection == null) throw new IllegalStateException("Connection is null"); if (connection == null) throw new NullPointerException("Connection is null");
ps = connection.prepareStatement(query); ps = connection.prepareStatement(query);
} catch (SQLException | IllegalStateException e) { } catch (SQLException | NullPointerException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@@ -6,6 +6,7 @@ import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.database.UserData; import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Color;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@@ -22,17 +23,22 @@ public abstract class SQLData extends Data {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
UserData data = new UserData(uniqueId); UserData data = new UserData(uniqueId);
try (PreparedStatement preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;")){ PreparedStatement preparedStatement = null;
try {
preparedStatement = preparedStatement("SELECT * FROM COSMETICDATABASE WHERE UUID = ?;");
preparedStatement.setString(1, uniqueId.toString()); preparedStatement.setString(1, uniqueId.toString());
try (ResultSet rs = preparedStatement.executeQuery()) { ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) { if (rs.next()) {
String rawData = rs.getString("COSMETICS"); String rawData = rs.getString("COSMETICS");
HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> cosmetics = deserializeData(rawData); HashMap<CosmeticSlot, Map.Entry<Cosmetic, Integer>> cosmetics = deserializeData(rawData);
data.setCosmetics(cosmetics); data.setCosmetics(cosmetics);
} }
}
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} finally {
try {
if (preparedStatement != null) preparedStatement.close();
} catch (SQLException e) {}
} }
return data; return data;
}); });
@@ -42,12 +48,18 @@ public abstract class SQLData extends Data {
@SuppressWarnings("resource") @SuppressWarnings("resource")
public void save(CosmeticUser user) { public void save(CosmeticUser user) {
Runnable run = () -> { Runnable run = () -> {
try (PreparedStatement preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);")) { PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("REPLACE INTO COSMETICDATABASE(UUID,COSMETICS) VALUES(?,?);");
preparedSt.setString(1, user.getUniqueId().toString()); preparedSt.setString(1, user.getUniqueId().toString());
preparedSt.setString(2, serializeData(user)); preparedSt.setString(2, serializeData(user));
preparedSt.executeUpdate(); preparedSt.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
} }
}; };
if (!HMCCosmeticsPlugin.getInstance().isDisabled()) { if (!HMCCosmeticsPlugin.getInstance().isDisabled()) {

View File

@@ -35,12 +35,10 @@ public class SQLiteData extends SQLData {
connection = DriverManager.getConnection("jdbc:sqlite:" + dataFolder); connection = DriverManager.getConnection("jdbc:sqlite:" + dataFolder);
openConnection(); openConnection();
try (PreparedStatement preparedStatement = connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " + connection.prepareStatement("CREATE TABLE IF NOT EXISTS `COSMETICDATABASE` " +
"(UUID varchar(36) PRIMARY KEY, " + "(UUID varchar(36) PRIMARY KEY, " +
"COSMETICS MEDIUMTEXT " + "COSMETICS MEDIUMTEXT " +
");")) { ");").execute();
preparedStatement.execute();
}
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -50,16 +48,27 @@ public class SQLiteData extends SQLData {
@SuppressWarnings("resource") @SuppressWarnings("resource")
public void clear(UUID uniqueId) { public void clear(UUID uniqueId) {
Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> { Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
try (PreparedStatement preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;")){ PreparedStatement preparedSt = null;
try {
preparedSt = preparedStatement("DELETE FROM COSMETICDATABASE WHERE UUID=?;");
preparedSt.setString(1, uniqueId.toString()); preparedSt.setString(1, uniqueId.toString());
preparedSt.executeUpdate(); preparedSt.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} finally {
try {
if (preparedSt != null) preparedSt.close();
} catch (SQLException e) {}
} }
}); });
} }
private void openConnection() throws SQLException { private void openConnection() throws SQLException {
// Bukkit.getScheduler().runTaskAsynchronously(HMCCosmeticsPlugin.getInstance(), () -> {
// ...
// });
// connection = DriverManager.getConnection("jdbc:mysql://" + DatabaseSettings.getHost() + ":" + DatabaseSettings.getPort() + "/" + DatabaseSettings.getDatabase(), setupProperties());
if (connection != null && !connection.isClosed()) return; if (connection != null && !connection.isClosed()) return;
// Close Connection if still active // Close Connection if still active
@@ -79,12 +88,9 @@ public class SQLiteData extends SQLData {
@Override @Override
public PreparedStatement preparedStatement(String query) { public PreparedStatement preparedStatement(String query) {
PreparedStatement ps = null; PreparedStatement ps = null;
if (!isConnectionOpen()) MessagesUtil.sendDebugMessages("Connection is not open");
try { try {
if (!isConnectionOpen()) {
MessagesUtil.sendDebugMessages("Connection is not open");
openConnection();
}
ps = connection.prepareStatement(query); ps = connection.prepareStatement(query);
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -14,18 +14,21 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import dev.triumphteam.gui.builder.item.ItemBuilder; import dev.triumphteam.gui.builder.item.ItemBuilder;
import dev.triumphteam.gui.components.GuiType; import dev.triumphteam.gui.components.GuiType;
import dev.triumphteam.gui.components.InventoryProvider;
import dev.triumphteam.gui.guis.Gui; import dev.triumphteam.gui.guis.Gui;
import dev.triumphteam.gui.guis.GuiItem; import dev.triumphteam.gui.guis.GuiItem;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer; import me.lojosho.hibiscuscommons.config.serializer.ItemSerializer;
import me.lojosho.hibiscuscommons.hooks.Hooks; import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.util.AdventureUtils; import me.lojosho.hibiscuscommons.util.AdventureUtils;
import me.lojosho.hibiscuscommons.util.StringUtils;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import me.lojosho.shaded.configurate.serialize.SerializationException; import me.lojosho.shaded.configurate.serialize.SerializationException;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -182,25 +185,18 @@ public class Menu {
if (taskid.get() != -1) Bukkit.getScheduler().cancelTask(taskid.get()); if (taskid.get() != -1) Bukkit.getScheduler().cancelTask(taskid.get());
}); });
Runnable openGuiTask = () -> {
gui.open(viewer);
updateMenu(viewer, cosmeticHolder, gui); // fixes shading? I know I do this twice but it's easier than writing a whole new class to deal with this shit
};
// API // API
if (cosmeticHolder instanceof CosmeticUser user) { if (cosmeticHolder instanceof CosmeticUser user) {
PlayerMenuOpenEvent event = new PlayerMenuOpenEvent(user, this); PlayerMenuOpenEvent event = new PlayerMenuOpenEvent(user, this);
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> { Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> Bukkit.getPluginManager().callEvent(event));
Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) return;
if (!event.isCancelled()) {
openGuiTask.run();
}
});
} }
// Internal // Internal
else {
Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), openGuiTask); Bukkit.getScheduler().runTask(HMCCosmeticsPlugin.getInstance(), () -> {
} gui.open(viewer);
updateMenu(viewer, cosmeticHolder, gui); // fixes shading? I know I do this twice but it's easier than writing a whole new class to deal with this shit
});
} }
private void updateMenu(Player viewer, CosmeticHolder cosmeticHolder, Gui gui) { private void updateMenu(Player viewer, CosmeticHolder cosmeticHolder, Gui gui) {

View File

@@ -3,6 +3,8 @@ package com.hibiscusmc.hmccosmetics.gui;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin; import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import lombok.Getter;
import lombok.Setter;
import me.lojosho.shaded.configurate.CommentedConfigurationNode; import me.lojosho.shaded.configurate.CommentedConfigurationNode;
import me.lojosho.shaded.configurate.ConfigurateException; import me.lojosho.shaded.configurate.ConfigurateException;
import me.lojosho.shaded.configurate.yaml.YamlConfigurationLoader; import me.lojosho.shaded.configurate.yaml.YamlConfigurationLoader;

View File

@@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.logging.Level;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Actions { public class Actions {
@@ -31,6 +30,7 @@ public class Actions {
private static final ActionCosmeticHide ACTION_HIDE = new ActionCosmeticHide(); private static final ActionCosmeticHide ACTION_HIDE = new ActionCosmeticHide();
private static final ActionCosmeticToggle ACTION_TOGGLE = new ActionCosmeticToggle(); private static final ActionCosmeticToggle ACTION_TOGGLE = new ActionCosmeticToggle();
public static Action getAction(@NotNull String id) { public static Action getAction(@NotNull String id) {
return actions.get(id.toUpperCase()); return actions.get(id.toUpperCase());
} }
@@ -45,13 +45,13 @@ public class Actions {
public static void runActions(Player viewer, CosmeticHolder cosmeticHolder, @NotNull List<String> raw) { public static void runActions(Player viewer, CosmeticHolder cosmeticHolder, @NotNull List<String> raw) {
for (String a : raw) { for (String a : raw) {
String id = StringUtils.substringBetween(a, "[", "]"); String id = StringUtils.substringBetween(a, "[", "]").toUpperCase();
String message = StringUtils.substringAfter(a, "] "); String message = StringUtils.substringAfter(a, "] ");
MessagesUtil.sendDebugMessages("ID is " + id + " // Raw Data is " + message); MessagesUtil.sendDebugMessages("ID is " + id + " // Raw Data is " + message);
if (id != null && isAction(id.toUpperCase())) { if (isAction(id)) {
getAction(id).run(viewer, cosmeticHolder, message); getAction(id).run(viewer, cosmeticHolder, message);
} else { } else {
MessagesUtil.sendDebugMessages("Invalid Action ID (" + id + ") used in menus (Full raw: '" + a + "'). Make sure all actions are properly typed out. Here are all possible actions: " + actions.keySet(), Level.WARNING); MessagesUtil.sendDebugMessages("Possible ids: " + actions.keySet());
} }
} }
} }

View File

@@ -1,20 +1,67 @@
package com.hibiscusmc.hmccosmetics.gui.special; package com.hibiscusmc.hmccosmetics.gui.special;
import com.hibiscusmc.hmccolor.HMCColorApi;
import com.hibiscusmc.hmccolor.shaded.gui.guis.Gui;
import com.hibiscusmc.hmccolor.shaded.gui.guis.GuiItem;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.AdventureUtils;
import me.lojosho.hibiscuscommons.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface DyeMenu { public class DyeMenu {
public static void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, Cosmetic cosmetic) {
/** if (!Hooks.isActiveHook("HMCColor")) {
* Overrideable method that is called when a player wishing to dye a menu. addCosmetic(viewer, cosmeticHolder, cosmetic, null);
* After the method is called, the menu plugin itself is supposed to handle everything else, including adding the cosmetic to the CosmeticHolder return;
* }
* @param viewer The player that is viewing the menu ItemStack originalItem = cosmetic.getItem();
* @param cosmeticHolder The CosmeticHolder that is being dyed (Can be different from the viewer) if (originalItem == null || !cosmetic.isDyeable()) return;
* @param cosmetic (The cosmetic that is wished to be dyed)
*/ Gui gui = HMCColorApi.createColorMenu(viewer);
void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic); gui.updateTitle(AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, StringUtils.parseStringToString(Settings.getDyeMenuName()))));
gui.setItem(Settings.getDyeMenuInputSlot(), new GuiItem(originalItem));
gui.setDefaultTopClickAction(event -> {
if (event.getSlot() == Settings.getDyeMenuOutputSlot()) {
ItemStack item = event.getInventory().getItem(Settings.getDyeMenuOutputSlot());
if (item == null) return;
Color color = NMSHandlers.getHandler().getUtilHandler().getColor(item);
if (color == null) return;
addCosmetic(viewer, cosmeticHolder, cosmetic, color);
event.setCancelled(true);
} else event.setCancelled(true);
});
gui.setPlayerInventoryAction(event -> event.setCancelled(true));
gui.setCloseGuiAction(event -> {});
gui.open(viewer);
}
public static void openMenu(@NotNull CosmeticUser user, Cosmetic cosmetic) {
Player player = user.getPlayer();
if (player == null) return;
openMenu(player, user, cosmetic);
}
private static void addCosmetic(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic, @Nullable Color color) {
cosmeticHolder.addCosmetic(cosmetic, color);
viewer.setItemOnCursor(new ItemStack(Material.AIR));
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
viewer.closeInventory();
cosmeticHolder.updateCosmetic(cosmetic.getSlot());
}, 2);
}
} }

View File

@@ -1,46 +0,0 @@
package com.hibiscusmc.hmccosmetics.gui.special;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class DyeMenuProvider {
private static DyeMenu instance = null;
/**
* Sets the provider of the DyeMenu. Check {@link DyeMenuProvider#hasMenuProvider()} before attempting to set this,
* it is locked once a dye menu has been set!
* @param dyeMenu The dye menu implementation that wishes to be the provider.
* @throws IllegalStateException IllegalStateException will be thrown if a dye menu provider already is set by another plugin.
*/
public static void setDyeMenuProvider(@NotNull DyeMenu dyeMenu) throws IllegalStateException {
if (instance != null) {
throw new IllegalStateException("DyeMenu Implementation has already been set by another plugin.");
}
instance = dyeMenu;
}
/**
* Called when wishing to dye a cosmetic to hand it off to the dye menu implementation
* @param viewer The viewer of the menu
* @param cosmeticHolder The cosmetic holder that the player viewer wishing to modify (could be themselves or another CosmeticHolder)
* @param cosmetic The cosmetic the user wishes to dye
* @throws IllegalStateException IllegalStateException will be thrown if the dye menu instance is null (Check {@link DyeMenuProvider#hasMenuProvider()} before calling)
*/
public static void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic) throws IllegalStateException {
if (instance == null) {
throw new IllegalStateException("Unable to open a dye menu without instance of it.");
}
instance.openMenu(viewer, cosmeticHolder, cosmetic);
}
/**
* Does HMCC have a dye menu provider already set?
* @return True if it is already set and locked; false if none have been set.
*/
public static boolean hasMenuProvider() {
return instance != null;
}
}

View File

@@ -1,58 +0,0 @@
package com.hibiscusmc.hmccosmetics.gui.special.impl;
import com.hibiscusmc.hmccolor.HMCColorApi;
import com.hibiscusmc.hmccolor.shaded.gui.guis.Gui;
import com.hibiscusmc.hmccolor.shaded.gui.guis.GuiItem;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.AdventureUtils;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class HMCColorDyeMenu implements DyeMenu {
@Override
public void openMenu(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic) {
ItemStack originalItem = cosmetic.getItem();
if (originalItem == null || !cosmetic.isDyeable()) return;
Gui gui = HMCColorApi.createColorMenu(viewer);
gui.updateTitle(AdventureUtils.MINI_MESSAGE.deserialize(Hooks.processPlaceholders(viewer, Settings.getDyeMenuName())));
gui.setItem(Settings.getDyeMenuInputSlot(), new GuiItem(originalItem));
gui.setDefaultTopClickAction(event -> {
if (event.getSlot() == Settings.getDyeMenuOutputSlot()) {
ItemStack item = event.getInventory().getItem(Settings.getDyeMenuOutputSlot());
if (item == null) return;
Color color = NMSHandlers.getHandler().getUtilHandler().getColor(item);
if (color == null) return;
addCosmetic(viewer, cosmeticHolder, cosmetic, color);
event.setCancelled(true);
} else event.setCancelled(true);
});
gui.setPlayerInventoryAction(event -> event.setCancelled(true));
gui.setCloseGuiAction(event -> {});
gui.open(viewer);
}
private void addCosmetic(@NotNull Player viewer, @NotNull CosmeticHolder cosmeticHolder, @NotNull Cosmetic cosmetic, @Nullable Color color) {
cosmeticHolder.addCosmetic(cosmetic, color);
viewer.setItemOnCursor(new ItemStack(Material.AIR));
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
viewer.closeInventory();
cosmeticHolder.updateCosmetic(cosmetic.getSlot());
}, 2);
}
}

View File

@@ -8,7 +8,6 @@ import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetics;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.gui.action.Actions; import com.hibiscusmc.hmccosmetics.gui.action.Actions;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu; import com.hibiscusmc.hmccosmetics.gui.special.DyeMenu;
import com.hibiscusmc.hmccosmetics.gui.special.DyeMenuProvider;
import com.hibiscusmc.hmccosmetics.gui.type.Type; import com.hibiscusmc.hmccosmetics.gui.type.Type;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
@@ -67,11 +66,14 @@ public class TypeCosmetic extends Type {
MessagesUtil.sendDebugMessages("Required click type: " + requiredClick); MessagesUtil.sendDebugMessages("Required click type: " + requiredClick);
MessagesUtil.sendDebugMessages("Click type: " + clickType.name()); MessagesUtil.sendDebugMessages("Click type: " + clickType.name());
boolean isRequiredClick = requiredClick.equalsIgnoreCase("ANY") || requiredClick.equalsIgnoreCase(clickType.name());
boolean isDyeClick = dyeClick.equalsIgnoreCase("ANY") || dyeClick.equalsIgnoreCase(clickType.name());
if (!isRequiredClick && !isDyeClick) {
MessagesUtil.sendMessage(viewer.getPlayer(), "invalid-click-type");
return;
}
final boolean isRequiredClick = requiredClick.equalsIgnoreCase("ANY") || requiredClick.equalsIgnoreCase(clickType.name()); if (!isRequiredClick && isDyeClick) isUnEquippingCosmetic = false;
final boolean isDyeClick = dyeClick.equalsIgnoreCase("ANY") || dyeClick.equalsIgnoreCase(clickType.name());
if (!isRequiredClick) isUnEquippingCosmetic = false;
List<String> actionStrings = new ArrayList<>(); List<String> actionStrings = new ArrayList<>();
ConfigurationNode actionConfig = config.node("actions"); ConfigurationNode actionConfig = config.node("actions");
@@ -103,11 +105,9 @@ public class TypeCosmetic extends Type {
} else { } else {
if (!actionConfig.node("on-equip").virtual()) actionStrings.addAll(actionConfig.node("on-equip").getList(String.class)); if (!actionConfig.node("on-equip").virtual()) actionStrings.addAll(actionConfig.node("on-equip").getList(String.class));
MessagesUtil.sendDebugMessages("on-equip"); MessagesUtil.sendDebugMessages("on-equip");
MessagesUtil.sendDebugMessages("Preparing for on-equip with the following checks:");
MessagesUtil.sendDebugMessages("CosmeticDyeable? " + cosmetic.isDyeable() + " / isDyeClick? " + isDyeClick + " / isHMCColorActive? " + Hooks.isActiveHook("HMCColor"));
// TODO: Redo this // TODO: Redo this
if (cosmetic.isDyeable() && isDyeClick && DyeMenuProvider.hasMenuProvider()) { if (cosmetic.isDyeable() && isDyeClick && Hooks.isActiveHook("HMCColor")) {
DyeMenuProvider.openMenu(viewer, cosmeticHolder, cosmetic); DyeMenu.openMenu(viewer, cosmeticHolder, cosmetic);
} else if (isRequiredClick) { } else if (isRequiredClick) {
cosmeticHolder.addCosmetic(cosmetic); cosmeticHolder.addCosmetic(cosmetic);
} }

View File

@@ -9,6 +9,7 @@ import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.TranslationUtil; import com.hibiscusmc.hmccosmetics.util.TranslationUtil;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.apache.commons.lang3.EnumUtils;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;

View File

@@ -20,6 +20,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;

View File

@@ -4,16 +4,22 @@ import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.api.events.PlayerCosmeticPostEquipEvent; import com.hibiscusmc.hmccosmetics.api.events.PlayerCosmeticPostEquipEvent;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.config.WardrobeSettings; import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils; import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils; import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import me.lojosho.hibiscuscommons.api.events.*; import me.lojosho.hibiscuscommons.api.events.*;
import me.lojosho.hibiscuscommons.nms.MinecraftVersion;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@@ -40,6 +46,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
public class PlayerGameListener implements Listener { public class PlayerGameListener implements Listener {
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onPlayerClick(@NotNull InventoryClickEvent event) { public void onPlayerClick(@NotNull InventoryClickEvent event) {
// || !event.getClickedInventory().getType().equals(InventoryType.PLAYER) // || !event.getClickedInventory().getType().equals(InventoryType.PLAYER)
@@ -94,17 +101,19 @@ public class PlayerGameListener implements Listener {
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> { Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> {
if (user.getEntity() == null || user.isInWardrobe()) return; // fixes disconnecting when in wardrobe (the entity stuff) if (user.getEntity() == null || user.isInWardrobe()) return; // fixes disconnecting when in wardrobe (the entity stuff)
if (Settings.getDisabledWorlds().contains(user.getEntity().getLocation().getWorld().getName())) { if (Settings.getDisabledWorlds().contains(user.getEntity().getLocation().getWorld().getName())) {
user.hideCosmetics(CosmeticUser.HiddenReason.WORLD); user.hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else { } else {
user.showCosmetics(CosmeticUser.HiddenReason.WORLD); user.showCosmetics(CosmeticUser.HiddenReason.WORLD);
} }
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK) && user.getUserBackpackManager() != null) {
user.respawnBackpack(); user.respawnBackpack();
}
if (user.hasCosmeticInSlot(CosmeticSlot.BALLOON)) {
user.respawnBalloon(); user.respawnBalloon();
}
user.updateCosmetic(); user.updateCosmetic();
}, 4); }, 2);
if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) || event.getCause().equals(PlayerTeleportEvent.TeleportCause.END_PORTAL)) return; if (event.getCause().equals(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) || event.getCause().equals(PlayerTeleportEvent.TeleportCause.END_PORTAL)) return;
} }
@@ -138,7 +147,8 @@ public class PlayerGameListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerHit(EntityDamageByEntityEvent event) { public void onPlayerHit(EntityDamageByEntityEvent event) {
Entity entity = event.getEntity(); Entity entity = event.getEntity();
if (!entity.getPersistentDataContainer().has(HMCCServerUtils.getCosmemeticMobKey(), PersistentDataType.BOOLEAN)) return; if (!entity.getPersistentDataContainer().has(new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmeticMob"), PersistentDataType.SHORT))
return;
event.setCancelled(true); event.setCancelled(true);
} }
@@ -156,6 +166,15 @@ public class PlayerGameListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return;
user.updateCosmetic(CosmeticSlot.BACKPACK);
user.updateCosmetic(CosmeticSlot.BALLOON);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerPoseChange(EntityPoseChangeEvent event) { public void onPlayerPoseChange(EntityPoseChangeEvent event) {
if (!(event.getEntity() instanceof Player player)) return; if (!(event.getEntity() instanceof Player player)) return;
@@ -345,15 +364,6 @@ public class PlayerGameListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEntityEvent event) {
final Player player = event.getPlayer();
final Entity entity = event.getRightClicked();
// Balloons are technically actual entities, so we need to cancel any interactions with them
if (!entity.getPersistentDataContainer().has(HMCCServerUtils.getCosmemeticMobKey(), PersistentDataType.BOOLEAN)) return;
event.setCancelled(true);
}
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerVanish(HibiscusPlayerVanishEvent event) { public void onPlayerVanish(HibiscusPlayerVanishEvent event) {
CosmeticUser user = CosmeticUsers.getUser(event.getPlayer()); CosmeticUser user = CosmeticUsers.getUser(event.getPlayer());

View File

@@ -1,101 +0,0 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Slf4j
public class PlayerMovementListener implements Listener {
private static final List<CosmeticSlot> MOVEMENT_COSMETICS = List.of(
CosmeticSlot.BACKPACK,
CosmeticSlot.BALLOON
);
// Player Id -> Small Location
private final Map<UUID, SmallLocation> locations = new HashMap<>();
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent ev) {
final Player player = ev.getPlayer();
final CosmeticUser user = CosmeticUsers.getUser(player);
if(user == null) {
return;
}
if(!updateDirtyLocation(ev.getPlayer(), ev.getTo())) {
return;
}
for(final CosmeticSlot slot : MOVEMENT_COSMETICS) {
user.updateMovementCosmetic(slot, ev.getFrom(), ev.getTo());
}
}
private boolean updateDirtyLocation(final Player player, final Location nextLoc) {
final SmallLocation previous = locations.computeIfAbsent(
player.getUniqueId(),
$ -> SmallLocation.fromLocation(nextLoc)
);
final SmallLocation next = SmallLocation.fromLocation(nextLoc);
if(next.distanceTo(previous) > 0.25) {
this.locations.put(player.getUniqueId(), next);
return true;
}
if(next.yawDistanceTo(previous) > 5) {
this.locations.put(player.getUniqueId(), next);
return true;
}
return false;
}
@EventHandler(priority = EventPriority.NORMAL)
public void onWorldChange(final PlayerChangedWorldEvent ev) {
this.locations.remove(ev.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerQuit(final PlayerQuitEvent ev) {
locations.remove(ev.getPlayer().getUniqueId());
}
record SmallLocation(
double x,
double y,
double z,
float yaw
) {
public double distanceTo(SmallLocation other) {
double dx = this.x - other.x;
double dy = this.y - other.y;
double dz = this.z - other.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
public float yawDistanceTo(SmallLocation other) {
float diff = Math.abs(this.yaw - other.yaw) % 360;
return diff > 180 ? 360 - diff : diff;
}
public static SmallLocation fromLocation(final Location location) {
return new SmallLocation(location.getX(), location.getY(), location.getZ(), location.getYaw());
}
}
}

View File

@@ -0,0 +1,27 @@
package com.hibiscusmc.hmccosmetics.listener;
import com.hibiscusmc.hmccosmetics.nms.CosmeticChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import net.minecraft.network.Connection;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class PlayerPacketListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
Channel channel = ((CraftPlayer) event.getPlayer()).getHandle().connection.connection.channel;
ChannelPipeline pipeline = channel.pipeline();
CosmeticChannelHandler channelHandler = new CosmeticChannelHandler(player);
for (String key : pipeline.toMap().keySet()) {
if (!(pipeline.get(key) instanceof Connection)) continue;
pipeline.addBefore(key, "hmccosmetics_channel_handler", channelHandler);
}
}
}

View File

@@ -0,0 +1,247 @@
package com.hibiscusmc.hmccosmetics.nms;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.mojang.datafixers.util.Pair;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.*;
import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
import net.minecraft.world.inventory.ClickType;
import net.minecraft.world.item.ItemStack;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftEquipmentSlot;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
public class CosmeticChannelHandler extends ChannelDuplexHandler {
private final Player player;
public CosmeticChannelHandler(Player player) {
this.player = player;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (!(msg instanceof Packet packet)) {
super.write(ctx, msg, promise);
return;
}
switch (packet) {
case ClientboundContainerSetContentPacket setContentPacket -> msg = handleMenuChange(setContentPacket);
case ClientboundContainerSetSlotPacket setSlotPacket -> msg = handleSlotChange(setSlotPacket);
case ClientboundSetEquipmentPacket equipmentPacket -> msg = handlePlayerEquipment(equipmentPacket);
case ClientboundSetPassengersPacket passengerPacket -> msg = handlePassengerSet(passengerPacket);
default -> {
}
}
if (msg == null) return;
else super.write(ctx, msg, promise);
}
private Packet<?> handleMenuChange(ClientboundContainerSetContentPacket packet) {
MessagesUtil.sendDebugMessages("Menu Initial ");
int windowId = packet.getContainerId();
NonNullList<ItemStack> slotData = NonNullList.create();
slotData.addAll(packet.getItems());
if (windowId != 0) return packet;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return packet;
HashMap<Integer, ItemStack> items = new HashMap<>();
if (!user.isInWardrobe()) for (Cosmetic cosmetic : user.getCosmetics()) if (cosmetic instanceof CosmeticArmorType armorType) {
boolean requireEmpty = Settings.getSlotOption(armorType.getEquipSlot()).isRequireEmpty();
boolean isAir = user.getPlayer().getInventory().getItem(armorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("Menu Fired (Checks) - " + armorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
items.put(HMCCInventoryUtils.getPacketArmorSlot(armorType.getEquipSlot()), CraftItemStack.asNMSCopy(user.getUserCosmeticItem(armorType)));
}
for (int slot = 0; slot < 46; slot++) {
if ((slot >= 5 && slot <= 8) || slot == 45) {
if (!items.containsKey(slot)) continue;
slotData.set(slot, items.get(slot));
if (Settings.isDebugMode()) MessagesUtil.sendDebugMessages("Set " + slot + " as " + items.get(slot));
}
}
MessagesUtil.sendDebugMessages("Menu Fired, updated cosmetics " + " on slotdata " + windowId + " with " + slotData.size());
return new ClientboundContainerSetContentPacket(0, packet.getStateId(), slotData, packet.getCarriedItem());
}
private Packet<?> handleSlotChange(ClientboundContainerSetSlotPacket packet) {
MessagesUtil.sendDebugMessages("SetSlot Initial ");
int windowId = packet.getContainerId();
if (windowId != 0) return packet;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return packet;
int slot = packet.getSlot();
MessagesUtil.sendDebugMessages("SetSlot Slot " + slot);
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slot);
EquipmentSlot equipmentSlot = HMCCInventoryUtils.getPacketArmorSlot(slot);
if (cosmeticSlot == null || equipmentSlot == null) return packet;
if (!user.hasCosmeticInSlot(cosmeticSlot)) return packet;
if (Settings.getSlotOption(equipmentSlot).isRequireEmpty()) {
if (!player.getInventory().getItem(equipmentSlot).getType().isAir()) return packet;
}
ItemStack item = CraftItemStack.asNMSCopy(user.getUserCosmeticItem(cosmeticSlot));
return new ClientboundContainerSetSlotPacket(0, packet.getStateId(), slot, item);
}
private Packet<?> handlePlayerEquipment(ClientboundSetEquipmentPacket packet) {
CosmeticUser user = CosmeticUsers.getUser(packet.getEntity());
if (user == null || user.isInWardrobe()) return packet;
List<Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack>> armor = packet.getSlots();
for (int i = 0; i < armor.size(); i++) {
Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack> pair = armor.get(i);
if (pair.getFirst() == net.minecraft.world.entity.EquipmentSlot.MAINHAND) {
if (user.getPlayer().getUniqueId() == player.getUniqueId())
continue; // When a player scrolls real fast, it messes up the mainhand. This fixes it
if (user.getPlayer() != null && user.getPlayer().isInvisible())
continue; // Fixes integration with GSit still showing mainhand even when hidden
armor.set(i, new Pair<>(pair.getFirst(), CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand())));
} else {
EquipmentSlot slot = CraftEquipmentSlot.getSlot(pair.getFirst());
if (slot == null) continue;
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.BukkitCosmeticSlot(slot);
if (cosmeticSlot == null) continue;
if (Settings.getSlotOption(slot).isRequireEmpty() && player.getInventory().getItem(slot).getType().isAir())
continue;
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(cosmeticSlot);
if (cosmeticArmor == null) continue;
ItemStack item = CraftItemStack.asNMSCopy(user.getUserCosmeticItem(cosmeticSlot));
if (item == null) continue;
armor.set(i, new Pair<>(pair.getFirst(), item));
}
}
MessagesUtil.sendDebugMessages("Equipment for " + user.getPlayer().getName() + " has been updated for " + player.getName());
return new ClientboundSetEquipmentPacket(packet.getEntity(), armor);
}
private Packet<?> handlePassengerSet(ClientboundSetPassengersPacket packet) {
CosmeticUser viewerUser = CosmeticUsers.getUser(player);
if (viewerUser == null || viewerUser.isInWardrobe()) return packet;
int ownerId = packet.getVehicle();
MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId);
Entity entity = HMCCServerUtils.getEntity(ownerId);
if (entity == null) return packet;
CosmeticUser user = CosmeticUsers.getUser(entity.getUniqueId());
if (user == null) return packet;
MessagesUtil.sendDebugMessages("Mount Packet Sent - " + user.getUniqueId());
if (!user.hasCosmeticInSlot(CosmeticSlot.BACKPACK)) return packet;
if (user.getUserBackpackManager() == null) return packet;
List<Integer> passengers = new ArrayList<>(user.getUserBackpackManager().getEntityManager().getIds());
for (int passenger : packet.getPassengers()) passengers.add(passenger);
int[] passengerIds = passengers.stream().mapToInt(Integer::intValue).toArray();
return (Packet<?>) NMSHandlers.getHandler().getPacketHandler().createMountPacket(ownerId, passengerIds);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof Packet packet)) {
super.channelRead(ctx, msg);
return;
}
switch (packet) {
case ServerboundContainerClickPacket clickPacket -> handleInventoryClick(clickPacket);
case ServerboundPlayerActionPacket playerActionPacket -> msg = handlePlayerAction(playerActionPacket);
case ServerboundSwingPacket swingPacket -> msg = handlePlayerArm(swingPacket);
case ServerboundUseItemOnPacket useItemOnPacket -> msg = handleEntityUse(useItemOnPacket);
default -> {
}
}
if (msg == null) return;
else super.channelRead(ctx, msg);
}
private void handleInventoryClick(ServerboundContainerClickPacket packet) {
ClickType clickType = packet.getClickType();
int slotClicked = packet.getSlotNum();
if (clickType != ClickType.PICKUP || slotClicked == -999) return;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return;
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slotClicked);
if (cosmeticSlot == null || !user.hasCosmeticInSlot(cosmeticSlot)) return;
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> user.updateCosmetic(cosmeticSlot), 1);
MessagesUtil.sendDebugMessages("Packet fired, updated cosmetic " + cosmeticSlot);
}
private Packet<?> handlePlayerAction(ServerboundPlayerActionPacket packet) {
ServerboundPlayerActionPacket.Action action = packet.getAction();
MessagesUtil.sendDebugMessages("EntityStatus Initial " + player.getEntityId() + " - " + action);
if (action != ServerboundPlayerActionPacket.Action.SWAP_ITEM_WITH_OFFHAND) return packet;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) {
MessagesUtil.sendDebugMessages("EntityStatus User is null");
return packet;
}
if (!user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) return packet;
return null;
}
private Packet<?> handlePlayerArm(ServerboundSwingPacket packet) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe() || !user.getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return packet;
Menu menu = user.getWardrobeManager().getLastOpenMenu();
if (menu == null) return packet;
menu.openMenu(user);
return null;
}
private Packet<?> handleEntityUse(ServerboundUseItemOnPacket packet) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe()) return packet;
else return null;
}
}

View File

@@ -1,229 +0,0 @@
package com.hibiscusmc.hmccosmetics.packets;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.gui.Menu;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
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.packets.PacketAction;
import me.lojosho.hibiscuscommons.packets.PacketInterface;
import me.lojosho.hibiscuscommons.packets.wrapper.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class CosmeticPacketInterface implements PacketInterface {
@Override
public @NotNull PacketAction writeContainerContent(@NotNull Player player, @NotNull ContainerContentWrapper wrapper) {
int windowId = wrapper.getWindowId();
MessagesUtil.sendDebugMessages("writeContainerContent (windowid: " + windowId + " )");
if (windowId != 0) return PacketAction.NOTHING;
List<ItemStack> slotData = wrapper.getSlotData();
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) return PacketAction.NOTHING;
HashMap<Integer, ItemStack> cosmeticItems = new HashMap<>();
if (!user.isInWardrobe()) {
for (Cosmetic cosmetic : user.getCosmetics()) {
if (cosmetic instanceof CosmeticArmorType armorType) {
boolean requireEmpty = Settings.getSlotOption(armorType.getEquipSlot()).isRequireEmpty();
boolean isAir = user.getPlayer().getInventory().getItem(armorType.getEquipSlot()).getType().isAir();
MessagesUtil.sendDebugMessages("Menu Fired (Checks) - " + armorType.getId() + " - " + requireEmpty + " - " + isAir);
if (requireEmpty && !isAir) continue;
cosmeticItems.put(HMCCInventoryUtils.getPacketArmorSlot(armorType.getEquipSlot()), user.getUserCosmeticItem(armorType));
}
}
}
for (int slot = 0; slot < 46; slot++) {
if ((slot >= 5 && slot <= 8) || slot == 45) {
if (!cosmeticItems.containsKey(slot)) continue;
slotData.set(slot, cosmeticItems.get(slot));
if (Settings.isDebugMode()) MessagesUtil.sendDebugMessages("Set " + slot + " as " + cosmeticItems.get(slot));
}
}
wrapper.setSlotData(slotData);
MessagesUtil.sendDebugMessages("Menu Fired, updated cosmetics " + " on slotdata " + windowId + " with " + slotData.size());
return PacketAction.CHANGED;
}
@Override
public @NotNull PacketAction writeSlotContent(@NotNull Player player, @NotNull SlotContentWrapper wrapper) {
int windowId = wrapper.getWindowId();
int slot = wrapper.getSlot();
ItemStack itemStack = wrapper.getItemStack();
MessagesUtil.sendDebugMessages("SetSlot Initial ");
if (windowId != 0) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
MessagesUtil.sendDebugMessages("SetSlot Slot " + slot);
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slot);
EquipmentSlot equipmentSlot = HMCCInventoryUtils.getPacketArmorSlot(slot);
if (cosmeticSlot == null || equipmentSlot == null) return PacketAction.NOTHING;
if (!user.hasCosmeticInSlot(cosmeticSlot)) return PacketAction.NOTHING;
if (Settings.getSlotOption(equipmentSlot).isRequireEmpty()) {
if (!player.getInventory().getItem(equipmentSlot).getType().isAir()) return PacketAction.NOTHING;
}
wrapper.setItemStack(user.getUserCosmeticItem(cosmeticSlot));
return PacketAction.CHANGED;
}
@Override
public @NotNull PacketAction writeEquipmentContent(@NotNull Player player, @NotNull EntityEquipmentWrapper wrapper) {
if (player.getEntityId() != wrapper.getEntityId()) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
Map<EquipmentSlot, ItemStack> armor = wrapper.getArmor();
for (Map.Entry<EquipmentSlot, ItemStack> armorSlot : armor.entrySet()) {
EquipmentSlot slot = armorSlot.getKey();
if (slot == EquipmentSlot.HAND) {
if (user.getPlayer().getUniqueId() == player.getUniqueId())
continue; // When a player scrolls real fast, it messes up the mainhand. This fixes it
if (user.getPlayer() != null && user.getPlayer().isInvisible())
continue; // Fixes integration with GSit still showing mainhand even when hidden
armor.put(slot, player.getInventory().getItemInMainHand());
} else {
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.BukkitCosmeticSlot(slot);
if (cosmeticSlot == null) continue;
if (Settings.getSlotOption(slot).isRequireEmpty() && player.getInventory().getItem(slot).getType().isAir())
continue;
CosmeticArmorType cosmeticArmor = (CosmeticArmorType) user.getCosmetic(cosmeticSlot);
if (cosmeticArmor == null) continue;
ItemStack item = user.getUserCosmeticItem(cosmeticSlot);
if (item == null) continue;
armor.put(slot, item);
}
}
wrapper.setArmor(armor);
MessagesUtil.sendDebugMessages("Equipment for " + user.getPlayer().getName() + " has been updated for " + player.getName());
return PacketAction.CHANGED;
}
@Override
public @NotNull PacketAction writePassengerContent(@NotNull Player player, @NotNull PassengerWrapper wrapper) {
// TODO: Figure out what to do with this, because with it in, it ruins backpacks (they keep getting thrown to random locations).
return PacketAction.NOTHING;
/*
CosmeticUser viewerUser = CosmeticUsers.getUser(player);
if (viewerUser == null || viewerUser.isInWardrobe()) return PacketAction.NOTHING;
int ownerId = wrapper.getOwner();
Optional<CosmeticUser> optionalCosmeticUser = CosmeticUsers.values().stream().filter(user -> user.getPlayer() != null).filter(user -> ownerId == user.getPlayer().getEntityId()).findFirst();
if (optionalCosmeticUser.isEmpty()) return PacketAction.NOTHING;
CosmeticUser user = optionalCosmeticUser.get();
Cosmetic backpackCosmetic = user.getCosmetic(CosmeticSlot.BACKPACK);
if (backpackCosmetic == null) return PacketAction.NOTHING;
if (!(backpackCosmetic instanceof CosmeticBackpackType cosmeticBackpackType)) return PacketAction.NOTHING;
if (user.getUniqueId().equals(viewerUser.getUniqueId())) {
if (cosmeticBackpackType.isFirstPersonCompadible()) return PacketAction.NOTHING;
}
if (user.getUserBackpackManager() == null) return PacketAction.NOTHING;
List<Integer> originalPassengers = wrapper.getPassengers();
List<Integer> passengers = new ArrayList<>(user.getUserBackpackManager().getEntityManager().getIds());
passengers.addAll(originalPassengers);
wrapper.setPassengers(passengers);
return PacketAction.CHANGED;
*/
}
@Override
public PacketAction readPlayerScale(@NotNull Player player, @NotNull PlayerScaleWrapper wrapper) {
int entityId = wrapper.getEntityId();
Player changedPlayer = Bukkit.getOnlinePlayers().stream()
.filter(onlinePlayer -> onlinePlayer.getEntityId() == entityId)
.findFirst()
.orElse(null);
if (changedPlayer == null) return PacketAction.NOTHING;
CosmeticUser cosmeticUser = CosmeticUsers.getUser(changedPlayer.getUniqueId());
if (cosmeticUser == null || cosmeticUser.isInWardrobe()) return PacketAction.NOTHING;
UserBackpackManager backpack = cosmeticUser.getUserBackpackManager();
if (backpack != null) {
for (int cosmeticId : backpack.getEntityManager().getIds()) {
HMCCPacketManager.sendEntityScalePacket(cosmeticId, wrapper.getScale(), Collections.singletonList(player));
}
}
return PacketAction.NOTHING;
}
@Override
public @NotNull PacketAction readInventoryClick(@NotNull Player player, @NotNull InventoryClickWrapper wrapper) {
int clickType = wrapper.getClickType();
int slotNumber = wrapper.getSlotNumber();
if (clickType != 0 || slotNumber == -999) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || user.isInWardrobe()) return PacketAction.NOTHING;
CosmeticSlot cosmeticSlot = HMCCInventoryUtils.NMSCosmeticSlot(slotNumber);
if (cosmeticSlot == null || !user.hasCosmeticInSlot(cosmeticSlot)) return PacketAction.NOTHING;
Bukkit.getScheduler().runTaskLater(HMCCosmeticsPlugin.getInstance(), () -> user.updateCosmetic(cosmeticSlot), 1);
MessagesUtil.sendDebugMessages("Packet fired, updated cosmetic " + cosmeticSlot);
return PacketAction.NOTHING;
}
@Override
public @NotNull PacketAction readPlayerAction(@NotNull Player player, @NotNull PlayerActionWrapper wrapper) {
if (!Settings.isPreventOffhandSwapping()) return PacketAction.NOTHING;
String actionType = wrapper.getActionType();
MessagesUtil.sendDebugMessages("EntityStatus Initial " + player.getEntityId() + " - " + actionType);
// If it's not SWAP_ITEM_WITH_OFFHAND, ignore
if (!actionType.equalsIgnoreCase("SWAP_ITEM_WITH_OFFHAND")) return PacketAction.NOTHING;
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null) {
MessagesUtil.sendDebugMessages("EntityStatus User is null");
return PacketAction.NOTHING;
}
if (!user.hasCosmeticInSlot(CosmeticSlot.OFFHAND)) return PacketAction.NOTHING;
return PacketAction.CANCELLED;
}
@Override
public @NotNull PacketAction readPlayerArm(@NotNull Player player, @NotNull PlayerSwingWrapper wrapper) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe() || !user.getWardrobeManager().getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return PacketAction.NOTHING;
Menu menu = user.getWardrobeManager().getLastOpenMenu();
if (menu == null) return PacketAction.NOTHING;
menu.openMenu(user);
return PacketAction.CANCELLED;
}
@Override
public @NotNull PacketAction readEntityHandle(@NotNull Player player, @NotNull PlayerInteractWrapper wrapper) {
CosmeticUser user = CosmeticUsers.getUser(player);
if (user == null || !user.isInWardrobe()) return PacketAction.NOTHING;
else return PacketAction.CANCELLED;
}
}

View File

@@ -10,11 +10,10 @@ import com.hibiscusmc.hmccosmetics.config.WardrobeSettings;
import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic; import com.hibiscusmc.hmccosmetics.cosmetic.Cosmetic;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticHolder;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticMovementBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.behavior.CosmeticUpdateBehavior;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticArmorType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticMainhandType;
import com.hibiscusmc.hmccosmetics.database.UserData; import com.hibiscusmc.hmccosmetics.database.UserData;
import com.hibiscusmc.hmccosmetics.gui.Menus; import com.hibiscusmc.hmccosmetics.gui.Menus;
import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager; import com.hibiscusmc.hmccosmetics.user.manager.UserBackpackManager;
@@ -23,6 +22,7 @@ import com.hibiscusmc.hmccosmetics.user.manager.UserWardrobeManager;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils; import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.modelengine.api.nms.NMSHandler;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.hooks.Hooks; import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.nms.NMSHandlers;
@@ -30,7 +30,7 @@ import me.lojosho.hibiscuscommons.util.InventoryUtils;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Location; import org.bukkit.FireworkEffect;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
@@ -39,7 +39,6 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*; import org.bukkit.inventory.meta.*;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -54,7 +53,7 @@ public class CosmeticUser implements CosmeticHolder {
private final HashMap<CosmeticSlot, Cosmetic> playerCosmetics = new HashMap<>(); private final HashMap<CosmeticSlot, Cosmetic> playerCosmetics = new HashMap<>();
private UserWardrobeManager userWardrobeManager; private UserWardrobeManager userWardrobeManager;
private UserBalloonManager userBalloonManager; private UserBalloonManager userBalloonManager;
@Getter @Nullable @Getter
private UserBackpackManager userBackpackManager; private UserBackpackManager userBackpackManager;
// Cosmetic Settings/Toggles // Cosmetic Settings/Toggles
@@ -99,7 +98,7 @@ public class CosmeticUser implements CosmeticHolder {
Color color = null; Color color = null;
if (colorRGBInt != -1) color = Color.fromRGB(colorRGBInt); // -1 is defined as no color; anything else is a color if (colorRGBInt != -1) color = Color.fromRGB(colorRGBInt); // -1 is defined as no color; anything else is a color
this.addCosmetic(cosmetic, color); this.addPlayerCosmetic(cosmetic, color);
} }
this.applyHiddenState(userData.getHiddenReasons()); this.applyHiddenState(userData.getHiddenReasons());
} }
@@ -112,7 +111,7 @@ public class CosmeticUser implements CosmeticHolder {
* This is used to help hooking plugins apply custom logic to the user. * This is used to help hooking plugins apply custom logic to the user.
*/ */
protected boolean applyCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color) { protected boolean applyCosmetic(@NotNull Cosmetic cosmetic, @Nullable Color color) {
this.addCosmetic(cosmetic, color); this.addPlayerCosmetic(cosmetic, color);
return true; return true;
} }
@@ -145,18 +144,13 @@ public class CosmeticUser implements CosmeticHolder {
showCosmetics(HiddenReason.GAMEMODE); showCosmetics(HiddenReason.GAMEMODE);
} }
if (bukkitPlayer != null && Settings.getDisabledWorlds().contains(bukkitPlayer.getLocation().getWorld().getName())) { if (bukkitPlayer != null && Settings.getDisabledWorlds().contains(getEntity().getLocation().getWorld().getName())) {
MessagesUtil.sendDebugMessages("Hiding Cosmetics due to world"); MessagesUtil.sendDebugMessages("Hiding Cosmetics due to world");
hideCosmetics(CosmeticUser.HiddenReason.WORLD); hideCosmetics(CosmeticUser.HiddenReason.WORLD);
} else if (this.isHidden(HiddenReason.WORLD)) { } else if (this.isHidden(HiddenReason.WORLD)) {
MessagesUtil.sendDebugMessages("Showing Cosmetics due to world"); MessagesUtil.sendDebugMessages("Showing Cosmetics due to world");
showCosmetics(HiddenReason.WORLD); showCosmetics(HiddenReason.WORLD);
} }
if (bukkitPlayer != null && bukkitPlayer.hasPotionEffect(PotionEffectType.INVISIBILITY)) {
hideCosmetics(HiddenReason.POTION);
}
if (Settings.isAllPlayersHidden()) { if (Settings.isAllPlayersHidden()) {
hideCosmetics(HiddenReason.DISABLED); hideCosmetics(HiddenReason.DISABLED);
} }
@@ -301,51 +295,22 @@ public class CosmeticUser implements CosmeticHolder {
} }
@Override @Override
public boolean updateCosmetic(@NotNull CosmeticSlot slot) { public void updateCosmetic(@NotNull CosmeticSlot slot) {
final Cosmetic cosmetic = playerCosmetics.get(slot); Cosmetic cosmetic = playerCosmetics.get(slot);
if(cosmetic == null) { if (cosmetic != null) {
return false; cosmetic.update(this);
}
} }
if(!(cosmetic instanceof CosmeticUpdateBehavior behavior)) { public void updateCosmetic(Cosmetic cosmetic) {
MessagesUtil.sendDebugMessages("Attempted to update cosmetic that does not implement CosmeticUpdateBehavior"); updateCosmetic(cosmetic.getSlot());
return false;
}
behavior.dispatchUpdate(this);
return true;
}
@Override
public boolean updateMovementCosmetic(@NotNull CosmeticSlot slot, @NotNull final Location from, @NotNull final Location to) {
final Cosmetic cosmetic = playerCosmetics.get(slot);
if(cosmetic == null) {
return false;
}
if(!(cosmetic instanceof CosmeticMovementBehavior behavior)) {
MessagesUtil.sendDebugMessages("Attempted to update cosmetic that does not implement CosmeticMovementBehavior");
return false;
}
behavior.dispatchMove(this, from, to);
return true;
}
public boolean updateCosmetic(@NotNull final Cosmetic cosmetic) {
return updateCosmetic(cosmetic.getSlot());
} }
public void updateCosmetic() { public void updateCosmetic() {
MessagesUtil.sendDebugMessages("updateCosmetic (All) - start"); MessagesUtil.sendDebugMessages("updateCosmetic (All) - start");
final HashMap<EquipmentSlot, ItemStack> items = new HashMap<>(); HashMap<EquipmentSlot, ItemStack> items = new HashMap<>();
for(final Cosmetic cosmetic : playerCosmetics.values()) { for (Cosmetic cosmetic : playerCosmetics.values()) {
if(!(cosmetic instanceof CosmeticUpdateBehavior behavior)) {
continue;
}
// defers item updates to end of operation
if (cosmetic instanceof CosmeticArmorType armorType) { if (cosmetic instanceof CosmeticArmorType armorType) {
if (isInWardrobe()) return; if (isInWardrobe()) return;
if (!(getEntity() instanceof HumanEntity humanEntity)) return; if (!(getEntity() instanceof HumanEntity humanEntity)) return;
@@ -357,22 +322,15 @@ public class CosmeticUser implements CosmeticHolder {
items.put(HMCCInventoryUtils.getEquipmentSlot(armorType.getSlot()), armorType.getItem(this)); items.put(HMCCInventoryUtils.getEquipmentSlot(armorType.getSlot()), armorType.getItem(this));
} else { } else {
behavior.dispatchUpdate(this); cosmetic.update(this);
} }
} }
if (items.isEmpty() || getEntity() == null) return;
final Entity entity = this.getEntity(); PacketManager.equipmentSlotUpdate(getEntity().getEntityId(), items, HMCCPacketManager.getViewers(getEntity().getLocation()));
if(!items.isEmpty() && entity != null) {
PacketManager.equipmentSlotUpdate(
entity.getEntityId(),
items,
HMCCPacketManager.getViewers(entity.getLocation())
);
MessagesUtil.sendDebugMessages("updateCosmetic (All) - end - " + items.size()); MessagesUtil.sendDebugMessages("updateCosmetic (All) - end - " + items.size());
} }
}
public ItemStack getUserCosmeticItem(@NotNull CosmeticSlot slot) { public ItemStack getUserCosmeticItem(CosmeticSlot slot) {
Cosmetic cosmetic = getCosmetic(slot); Cosmetic cosmetic = getCosmetic(slot);
if (cosmetic == null) return new ItemStack(Material.AIR); if (cosmetic == null) return new ItemStack(Material.AIR);
return getUserCosmeticItem(cosmetic); return getUserCosmeticItem(cosmetic);
@@ -387,7 +345,7 @@ public class CosmeticUser implements CosmeticHolder {
if (cosmetic instanceof CosmeticArmorType armorType) { if (cosmetic instanceof CosmeticArmorType armorType) {
item = armorType.getItem(this, cosmetic.getItem()); item = armorType.getItem(this, cosmetic.getItem());
} }
if (cosmetic instanceof CosmeticBackpackType) { if (cosmetic instanceof CosmeticBackpackType || cosmetic instanceof CosmeticMainhandType) {
item = cosmetic.getItem(); item = cosmetic.getItem();
} }
if (cosmetic instanceof CosmeticBalloonType) { if (cosmetic instanceof CosmeticBalloonType) {
@@ -645,7 +603,7 @@ public class CosmeticUser implements CosmeticHolder {
* @return Entity * @return Entity
*/ */
public Entity getEntity() { public Entity getEntity() {
return getPlayer(); return Bukkit.getEntity(uniqueId);
} }
public Color getCosmeticColor(CosmeticSlot slot) { public Color getCosmeticColor(CosmeticSlot slot) {
@@ -668,12 +626,7 @@ public class CosmeticUser implements CosmeticHolder {
if (isInWardrobe() && !ignoreWardrobe) { if (isInWardrobe() && !ignoreWardrobe) {
if (WardrobeSettings.isTryCosmeticsInWardrobe() && userWardrobeManager.getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return true; if (WardrobeSettings.isTryCosmeticsInWardrobe() && userWardrobeManager.getWardrobeStatus().equals(UserWardrobeManager.WardrobeStatus.RUNNING)) return true;
} }
final Player player = getPlayer(); return getEntity().hasPermission(cosmetic.getPermission());
if (player != null) return player.hasPermission(cosmetic.getPermission());
// This sucks, but basically if we can find a player, use that. If not, try to find the entity. If it can't find the entity, just return false.
final Entity entity = getEntity();
if (entity != null) return entity.hasPermission(cosmetic.getPermission());
return false;
} }
public void hidePlayer() { public void hidePlayer() {

View File

@@ -5,21 +5,22 @@ import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBackpackType;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.modelengine.api.ModelEngineAPI;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.util.ServerUtils; import me.lojosho.hibiscuscommons.util.ServerUtils;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level;
public class UserBackpackManager { public class UserBackpackManager {
@@ -30,7 +31,7 @@ public class UserBackpackManager {
private ArrayList<Integer> particleCloud = new ArrayList<>(); private ArrayList<Integer> particleCloud = new ArrayList<>();
@Getter @Getter
private final CosmeticUser user; private final CosmeticUser user;
@Getter @Nullable @Getter
private UserEntity entityManager; private UserEntity entityManager;
public UserBackpackManager(CosmeticUser user) { public UserBackpackManager(CosmeticUser user) {
@@ -55,15 +56,8 @@ public class UserBackpackManager {
getEntityManager().setIds(List.of(invisibleArmorStand)); getEntityManager().setIds(List.of(invisibleArmorStand));
getEntityManager().teleport(user.getEntity().getLocation()); getEntityManager().teleport(user.getEntity().getLocation());
List<Player> outsideViewers = getEntityManager().getViewers(); List<Player> outsideViewers = getEntityManager().getViewers();
HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), getFirstArmorStandId(), EntityType.ARMOR_STAND, UUID.randomUUID(), getEntityManager().getViewers());
HMCCPacketManager.spawnInvisibleArmorstand(getFirstArmorStandId(), user.getEntity().getLocation(), UUID.randomUUID(), outsideViewers); HMCCPacketManager.sendArmorstandMetadata(getFirstArmorStandId(), outsideViewers);
if (user.getPlayer() != null) {
AttributeInstance scaleAttribute = user.getPlayer().getAttribute(Attribute.GENERIC_SCALE);
if (scaleAttribute != null) {
HMCCPacketManager.sendEntityScalePacket(getFirstArmorStandId(), scaleAttribute.getValue(), outsideViewers);
}
}
Entity entity = user.getEntity(); Entity entity = user.getEntity();
@@ -81,7 +75,8 @@ public class UserBackpackManager {
if (cosmeticBackpackType.isFirstPersonCompadible()) { if (cosmeticBackpackType.isFirstPersonCompadible()) {
for (int i = particleCloud.size(); i < cosmeticBackpackType.getHeight(); i++) { for (int i = particleCloud.size(); i < cosmeticBackpackType.getHeight(); i++) {
int entityId = ServerUtils.getNextEntityId(); int entityId = ServerUtils.getNextEntityId();
HMCCPacketManager.spawnCloudAndHandleEffect(entityId, user.getEntity().getLocation(), UUID.randomUUID(), HMCCPacketManager.getViewers(user.getEntity().getLocation())); HMCCPacketManager.sendEntitySpawnPacket(user.getEntity().getLocation(), entityId, EntityType.AREA_EFFECT_CLOUD, UUID.randomUUID());
HMCCPacketManager.sendCloudEffect(entityId, HMCCPacketManager.getViewers(user.getEntity().getLocation()));
this.particleCloud.add(entityId); this.particleCloud.add(entityId);
} }
// Copied code from updating the backpack // Copied code from updating the backpack

View File

@@ -5,7 +5,6 @@ import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType; import com.hibiscusmc.hmccosmetics.cosmetic.types.CosmeticBalloonType;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCServerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.ModelEngineAPI;
@@ -50,8 +49,7 @@ public class UserBalloonManager {
e.setSmall(true); e.setSmall(true);
e.setMarker(true); e.setMarker(true);
e.setPersistent(false); e.setPersistent(false);
e.setAI(false); e.getPersistentDataContainer().set(new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmeticMob"), PersistentDataType.SHORT, Short.valueOf("1"));
e.getPersistentDataContainer().set(HMCCServerUtils.getCosmemeticMobKey(), PersistentDataType.BOOLEAN, true);
}); });
} }
@@ -101,12 +99,7 @@ public class UserBalloonManager {
} }
public void remove() { public void remove() {
// This code is like a brick road, always bumpy. pufferfish.destroyPufferfish();
// Basically, the balloon viewers ignore people in wardrobe, which well, if your the user in the wardrobe, ain't including you.
// This manually passes in the viewers for it to destroy, which includes the person in the wardrobe
if (user.getPlayer() != null && user.isInWardrobe()) pufferfish.destroyPufferfish(List.of(user.getPlayer()));
else pufferfish.destroyPufferfish();
if (balloonType == BalloonType.MODELENGINE) { if (balloonType == BalloonType.MODELENGINE) {
final ModeledEntity entity = ModelEngineAPI.getModeledEntity(modelEntity); final ModeledEntity entity = ModelEngineAPI.getModeledEntity(modelEntity);
if (entity == null) { if (entity == null) {

View File

@@ -1,12 +1,17 @@
package com.hibiscusmc.hmccosmetics.user.manager; package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.nms.NMSHandlers; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -21,7 +26,6 @@ public class UserBalloonPufferfish extends UserEntity {
public UserBalloonPufferfish(UUID owner, int pufferFishEntityId, UUID uuid) { public UserBalloonPufferfish(UUID owner, int pufferFishEntityId, UUID uuid) {
super(owner); super(owner);
this.pufferFishEntityId = pufferFishEntityId; this.pufferFishEntityId = pufferFishEntityId;
setIds(List.of(pufferFishEntityId));
this.uuid = uuid; this.uuid = uuid;
} }
@@ -31,11 +35,8 @@ public class UserBalloonPufferfish extends UserEntity {
} }
public void spawnPufferfish(Location location, List<Player> sendTo) { public void spawnPufferfish(Location location, List<Player> sendTo) {
NMSHandlers.getHandler().getPacketHandler().sendInvisibleEntity(pufferFishEntityId, EntityType.PUFFERFISH, location, uuid, sendTo);
/*
HMCCPacketManager.sendEntitySpawnPacket(location, pufferFishEntityId, EntityType.PUFFERFISH, uuid, sendTo); HMCCPacketManager.sendEntitySpawnPacket(location, pufferFishEntityId, EntityType.PUFFERFISH, uuid, sendTo);
HMCCPacketManager.sendInvisibilityPacket(pufferFishEntityId, sendTo); HMCCPacketManager.sendInvisibilityPacket(pufferFishEntityId, sendTo);
*/
} }
public void destroyPufferfish() { public void destroyPufferfish() {
@@ -44,12 +45,6 @@ public class UserBalloonPufferfish extends UserEntity {
destroyed = true; destroyed = true;
} }
public void destroyPufferfish(List<Player> viewers) {
HMCCPacketManager.sendEntityDestroyPacket(pufferFishEntityId, viewers);
//getViewers().clear();
destroyed = true;
}
@Override @Override
public List<Player> refreshViewers(Location location) { public List<Player> refreshViewers(Location location) {
if (destroyed) return List.of(); //Prevents refreshing a destroyed entity if (destroyed) return List.of(); //Prevents refreshing a destroyed entity

View File

@@ -1,9 +1,8 @@
package com.hibiscusmc.hmccosmetics.user.manager; package com.hibiscusmc.hmccosmetics.user.manager;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCPlayerUtils;
import com.hibiscusmc.hmccosmetics.util.MessagesUtil; import com.hibiscusmc.hmccosmetics.util.MessagesUtil;
import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager; import com.hibiscusmc.hmccosmetics.util.packets.HMCCPacketManager;
import lombok.Getter; import lombok.Getter;
@@ -13,7 +12,9 @@ import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class UserEntity { public class UserEntity {
@@ -39,66 +40,39 @@ public class UserEntity {
} }
public List<Player> refreshViewers(Location location) { public List<Player> refreshViewers(Location location) {
//Prevents mass refreshes if (System.currentTimeMillis() - viewerLastUpdate <= 1000) return List.of(); //Prevents mass refreshes
//if(System.currentTimeMillis() - viewerLastUpdate <= 3000) { ArrayList<Player> newPlayers = new ArrayList<>();
// return List.of(); ArrayList<Player> removePlayers = new ArrayList<>();
//} List<Player> players = HMCCPacketManager.getViewers(location);
Entity ownerPlayer = Bukkit.getEntity(owner); Entity ownerPlayer = Bukkit.getEntity(owner);
if (ownerPlayer == null) { if (ownerPlayer == null) {
MessagesUtil.sendDebugMessages("Owner is null (refreshViewers), returning empty list"); MessagesUtil.sendDebugMessages("Owner is null (refreshViewers), returning empty list");
return List.of(); return List.of();
} }
final List<Player> players = HMCCosmeticsPlugin.getInstance()
.getPlayerSearchManager()
.getPlayersInRange(location, Settings.getViewDistance());
final ArrayList<UUID> newPlayerIds = new ArrayList<>();
final ArrayList<UUID> removePlayerIds = new ArrayList<>();
// Go through all nearby players, check if they are new to the viewers list.
for (Player player : players) { for (Player player : players) {
CosmeticUser user = CosmeticUsers.getUser(player); CosmeticUser user = CosmeticUsers.getUser(player);
if( if (user != null && owner != user.getUniqueId() && user.isInWardrobe() && !player.canSee(ownerPlayer)) { // Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
user != null removePlayers.add(player);
&& owner != user.getUniqueId() HMCCPacketManager.sendEntityDestroyPacket(ids, List.of(player));
&& user.isInWardrobe()
// Fixes issue where players in wardrobe would see other players cosmetics if they were not in wardrobe
&& !player.canSee(ownerPlayer)
) {
removePlayerIds.add(player.getUniqueId());
continue; continue;
} }
if (!viewers.contains(player)) { if (!viewers.contains(player)) {
viewers.add(player); viewers.add(player);
newPlayerIds.add(player.getUniqueId()); newPlayers.add(player);
continue;
} }
} // bad loopdy loops
// Basically, if they are not nearby, they are still in the viewers and we need to kick em to the curb
for (Player viewerPlayer : viewers) { for (Player viewerPlayer : viewers) {
if (!players.contains(viewerPlayer)) { if (!players.contains(viewerPlayer)) {
removePlayerIds.add(viewerPlayer.getUniqueId()); removePlayers.add(viewerPlayer);
HMCCPacketManager.sendEntityDestroyPacket(ids, List.of(viewerPlayer));
}
} }
} }
// If there are players for removal, send the packets to them
if (!removePlayerIds.isEmpty()) {
final List<Player> removePlayers = removePlayerIds.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.toList();
HMCCPacketManager.sendEntityDestroyPacket(ids, removePlayers);
viewers.removeAll(removePlayers); viewers.removeAll(removePlayers);
} setViewerLastUpdate(System.currentTimeMillis());
return newPlayers;
this.setViewerLastUpdate(System.currentTimeMillis());
return newPlayerIds.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.toList();
} }
public void teleport(Location location) { public void teleport(Location location) {

View File

@@ -20,13 +20,12 @@ import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
@@ -118,8 +117,6 @@ public class UserWardrobeManager {
// Armorstand // Armorstand
HMCCPacketManager.sendEntitySpawnPacket(viewingLocation, ARMORSTAND_ID, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer); HMCCPacketManager.sendEntitySpawnPacket(viewingLocation, ARMORSTAND_ID, EntityType.ARMOR_STAND, UUID.randomUUID(), viewer);
HMCCPacketManager.sendArmorstandMetadata(ARMORSTAND_ID, viewer); HMCCPacketManager.sendArmorstandMetadata(ARMORSTAND_ID, viewer);
NMSHandlers.getHandler().getPacketHandler().sendTeleportPacket(ARMORSTAND_ID, viewingLocation.getX(), viewingLocation.getY(), viewingLocation.getZ(), viewingLocation.getYaw(), viewingLocation.getPitch(), false, viewer);
//NMSHandlers.getHandler().getPacketHandler().sendLookAtPacket(ARMORSTAND_ID, viewingLocation, viewer);
HMCCPacketManager.sendRotateHeadPacket(ARMORSTAND_ID, viewingLocation, viewer); HMCCPacketManager.sendRotateHeadPacket(ARMORSTAND_ID, viewingLocation, viewer);
// Player // Player
@@ -142,10 +139,6 @@ public class UserWardrobeManager {
HMCCPacketManager.sendPlayerOverlayPacket(NPC_ID, viewer); HMCCPacketManager.sendPlayerOverlayPacket(NPC_ID, viewer);
MessagesUtil.sendDebugMessages("Spawned Fake Player on " + npcLocation); MessagesUtil.sendDebugMessages("Spawned Fake Player on " + npcLocation);
NMSHandlers.getHandler().getPacketHandler().sendScoreboardHideNamePacket(player, npcName); NMSHandlers.getHandler().getPacketHandler().sendScoreboardHideNamePacket(player, npcName);
AttributeInstance scaleAttribute = user.getPlayer().getAttribute(Attribute.GENERIC_SCALE);
if (scaleAttribute != null) {
HMCCPacketManager.sendEntityScalePacket(NPC_ID, scaleAttribute.getValue(), viewer);
}
}, 4); }, 4);
// Location // Location
@@ -183,9 +176,9 @@ public class UserWardrobeManager {
Component message = MessagesUtil.processStringNoKey(player, WardrobeSettings.getBossbarMessage()); Component message = MessagesUtil.processStringNoKey(player, WardrobeSettings.getBossbarMessage());
bossBar = BossBar.bossBar(message, progress, WardrobeSettings.getBossbarColor(), WardrobeSettings.getBossbarOverlay()); bossBar = BossBar.bossBar(message, progress, WardrobeSettings.getBossbarColor(), WardrobeSettings.getBossbarOverlay());
//Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player); Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
player.showBossBar(bossBar); target.showBossBar(bossBar);
} }
if (WardrobeSettings.isEnterOpenMenu()) { if (WardrobeSettings.isEnterOpenMenu()) {
@@ -241,7 +234,7 @@ public class UserWardrobeManager {
// NPC // NPC
if (user.isBalloonSpawned()) user.getBalloonManager().sendRemoveLeashPacket(); if (user.isBalloonSpawned()) user.getBalloonManager().sendRemoveLeashPacket();
HMCCPacketManager.sendEntityDestroyPacket(NPC_ID, viewer); // Success HMCCPacketManager.sendEntityDestroyPacket(NPC_ID, viewer); // Success
HMCCPacketManager.sendRemovePlayerPacket(player, WARDROBE_UUID, viewer); // Success HMCCPacketManager.sendRemovePlayerPacket(WARDROBE_UUID, viewer); // Success
// Player // Player
HMCCPacketManager.sendCameraPacket(player.getEntityId(), viewer); HMCCPacketManager.sendCameraPacket(player.getEntityId(), viewer);
@@ -287,8 +280,9 @@ public class UserWardrobeManager {
HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), items, viewer); HMCCPacketManager.equipmentSlotUpdate(player.getEntityId(), items, viewer);
if (WardrobeSettings.isEnabledBossbar()) { if (WardrobeSettings.isEnabledBossbar()) {
//Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player); Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
player.hideBossBar(bossBar);
target.hideBossBar(bossBar);
} }
user.updateCosmetic(); user.updateCosmetic();
@@ -320,10 +314,8 @@ public class UserWardrobeManager {
HMCCPacketManager.sendRotateHeadPacket(NPC_ID, location, viewer); HMCCPacketManager.sendRotateHeadPacket(NPC_ID, location, viewer);
user.hidePlayer(); user.hidePlayer();
int rotationSpeed = WardrobeSettings.getRotationSpeed(); int rotationSpeed = WardrobeSettings.getRotationSpeed();
int newYaw = HMCCServerUtils.getNextYaw(yaw - 30, rotationSpeed); location.setYaw(HMCCServerUtils.getNextYaw(yaw - 30, rotationSpeed));
location.setYaw(newYaw); HMCCPacketManager.sendRotationPacket(NPC_ID, location, true, viewer);
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(NPC_ID, newYaw, 0, false, viewer);
HMCCPacketManager.sendRotationPacket(NPC_ID, newYaw, true, viewer);
int nextyaw = HMCCServerUtils.getNextYaw(yaw, rotationSpeed); int nextyaw = HMCCServerUtils.getNextYaw(yaw, rotationSpeed);
data.set(nextyaw); data.set(nextyaw);
@@ -331,10 +323,11 @@ public class UserWardrobeManager {
HMCCPacketManager.equipmentSlotUpdate(NPC_ID, user, slot, viewer); HMCCPacketManager.equipmentSlotUpdate(NPC_ID, user, slot, viewer);
} }
// Handle backpacks
if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK) && user.getUserBackpackManager() != null) { if (user.hasCosmeticInSlot(CosmeticSlot.BACKPACK) && user.getUserBackpackManager() != null) {
HMCCPacketManager.sendTeleportPacket(user.getUserBackpackManager().getFirstArmorStandId(), location, false, viewer); HMCCPacketManager.sendTeleportPacket(user.getUserBackpackManager().getFirstArmorStandId(), location, false, viewer);
HMCCPacketManager.ridingMountPacket(NPC_ID, user.getUserBackpackManager().getFirstArmorStandId(), viewer); HMCCPacketManager.ridingMountPacket(NPC_ID, user.getUserBackpackManager().getFirstArmorStandId(), viewer);
user.getUserBackpackManager().getEntityManager().setRotation(nextyaw); //user.getUserBackpackManager().getEntityManager().setRotation(nextyaw);
HMCCPacketManager.sendEntityDestroyPacket(user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers); HMCCPacketManager.sendEntityDestroyPacket(user.getUserBackpackManager().getFirstArmorStandId(), outsideViewers);
} }
@@ -366,5 +359,4 @@ public class UserWardrobeManager {
RUNNING, RUNNING,
STOPPING, STOPPING,
} }
} }

View File

@@ -50,6 +50,18 @@ public class HMCCInventoryUtils {
}; };
} }
// public static CosmeticSlot getItemSlotToCosmeticSlot(final EnumWrappers.ItemSlot slot) {
// return switch (slot) {
// case HEAD -> CosmeticSlot.HELMET;
// case CHEST -> CosmeticSlot.CHESTPLATE;
// case LEGS -> CosmeticSlot.LEGGINGS;
// case FEET -> CosmeticSlot.BOOTS;
// case OFFHAND -> CosmeticSlot.OFFHAND;
// case MAINHAND -> CosmeticSlot.MAINHAND;
// default -> null;
// };
// }
public static CosmeticSlot BukkitCosmeticSlot(EquipmentSlot slot) { public static CosmeticSlot BukkitCosmeticSlot(EquipmentSlot slot) {
return switch (slot) { return switch (slot) {
case HAND -> CosmeticSlot.MAINHAND; case HAND -> CosmeticSlot.MAINHAND;
@@ -118,6 +130,32 @@ public class HMCCInventoryUtils {
return SLOT_MAP.get(slot); return SLOT_MAP.get(slot);
} }
// 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) { public static boolean isCosmeticItem(ItemStack itemStack) {
if (itemStack == null) return false; if (itemStack == null) return false;
itemStack = itemStack.clone(); itemStack = itemStack.clone();

View File

@@ -1,6 +1,5 @@
package com.hibiscusmc.hmccosmetics.util; package com.hibiscusmc.hmccosmetics.util;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import com.owen1212055.particlehelper.api.particle.MultiParticle; import com.owen1212055.particlehelper.api.particle.MultiParticle;
import com.owen1212055.particlehelper.api.particle.Particle; import com.owen1212055.particlehelper.api.particle.Particle;
import com.owen1212055.particlehelper.api.particle.types.*; import com.owen1212055.particlehelper.api.particle.types.*;
@@ -10,8 +9,6 @@ import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.math.BigInteger; import java.math.BigInteger;
@@ -21,20 +18,6 @@ public class HMCCServerUtils {
private static String COLOR_CHAR = "&"; private static String COLOR_CHAR = "&";
/**
* Converts a bukkit gamemode into an integer for use in packets
* @param gamemode Bukkit gamemode to convert.
* @return int of the gamemode
*/
public static int convertGamemode(final GameMode gamemode) {
return switch (gamemode) {
case SURVIVAL -> 0;
case CREATIVE -> 1;
case ADVENTURE -> 2;
case SPECTATOR -> 3;
};
}
public static org.bukkit.entity.Entity getEntity(int entityId) { public static org.bukkit.entity.Entity getEntity(int entityId) {
return NMSHandlers.getHandler().getUtilHandler().getEntity(entityId); return NMSHandlers.getHandler().getUtilHandler().getEntity(entityId);
} }
@@ -160,8 +143,4 @@ public class HMCCServerUtils {
} }
return nextYaw; return nextYaw;
} }
public static NamespacedKey getCosmemeticMobKey() {
return new NamespacedKey(HMCCosmeticsPlugin.getInstance(), "cosmeticmob");
}
} }

View File

@@ -7,6 +7,7 @@ import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.util.AdventureUtils; import me.lojosho.hibiscuscommons.util.AdventureUtils;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.title.Title; import net.kyori.adventure.title.Title;
@@ -42,35 +43,41 @@ public class MessagesUtil {
public static void sendMessage(Player player, String key) { public static void sendMessage(Player player, String key) {
Component finalMessage = processString(player, key); Component finalMessage = processString(player, key);
if (finalMessage == null) return; if (finalMessage == null) return;
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
player.sendMessage(finalMessage); target.sendMessage(finalMessage);
} }
public static void sendMessage(CommandSender sender, String key) { public static void sendMessage(CommandSender sender, String key) {
Component finalMessage = processString(null, key); Component finalMessage = processString(null, key);
if (finalMessage == null) return; if (finalMessage == null) return;
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).sender(sender);
sender.sendMessage(finalMessage); target.sendMessage(finalMessage);
} }
public static void sendMessage(Player player, String key, TagResolver placeholder) { public static void sendMessage(Player player, String key, TagResolver placeholder) {
Component finalMessage = processString(player, key, placeholder); Component finalMessage = processString(player, key, placeholder);
if (finalMessage == null) return; if (finalMessage == null) return;
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
player.sendMessage(finalMessage); target.sendMessage(finalMessage);
} }
public static void sendMessageNoKey(Player player, String message) { public static void sendMessageNoKey(Player player, String message) {
Component finalMessage = processStringNoKey(player, message); Component finalMessage = processStringNoKey(player, message);
if (finalMessage == null) return; if (finalMessage == null) return;
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
player.sendMessage(finalMessage); target.sendMessage(finalMessage);
} }
public static void sendActionBar(Player player, String key) { public static void sendActionBar(Player player, String key) {
Component finalMessage = processString(player, key); Component finalMessage = processString(player, key);
if (finalMessage == null) return; if (finalMessage == null) return;
player.sendActionBar(finalMessage); Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
target.sendActionBar(finalMessage);
} }
public static void sendTitle(Player player, String message) { public static void sendTitle(Player player, String message) {
@@ -78,10 +85,12 @@ public class MessagesUtil {
} }
public static void sendTitle(Player player, String message, int fadein, int stay, int fadeout) { public static void sendTitle(Player player, String message, int fadein, int stay, int fadeout) {
Audience target = BukkitAudiences.create(HMCCosmeticsPlugin.getInstance()).player(player);
Title.Times times = Title.Times.times(Duration.ofMillis(fadein), Duration.ofMillis(stay), Duration.ofMillis(fadeout)); Title.Times times = Title.Times.times(Duration.ofMillis(fadein), Duration.ofMillis(stay), Duration.ofMillis(fadeout));
Title title = Title.title(processStringNoKey(player, message), Component.empty(), times); Title title = Title.title(processStringNoKey(player, message), Component.empty(), times);
player.showTitle(title); target.showTitle(title);
} }
public static Component processString(Player player, String key) { public static Component processString(Player player, String key) {

View File

@@ -1,148 +0,0 @@
package com.hibiscusmc.hmccosmetics.util;
import java.util.ArrayList;
import java.util.List;
public class Octree<T> {
private static final int MAX_CAPACITY = 8;
private BoundingBox boundary;
private List<Entry> points;
private Octree<T>[] children;
private boolean isDivided;
public Octree(BoundingBox boundary) {
this.boundary = boundary;
this.points = new ArrayList<>();
this.isDivided = false;
}
public boolean insert(Point3D position, T data) {
if (!boundary.contains(position)) {
return false;
}
if (points.size() < MAX_CAPACITY && !isDivided) {
points.add(new Entry(position, data));
return true;
}
if (!isDivided) {
subdivide();
}
for (Octree<T> child : children) {
if (child.insert(position, data)) {
return true;
}
}
return false;
}
public boolean remove(Point3D point, T player) {
if (!boundary.contains(point)) {
return false;
}
if (points.size() < MAX_CAPACITY && !isDivided) {
points.removeIf(entry -> entry.position.equals(point) && entry.data.equals(player));
return true;
}
if (!isDivided) {
return false;
}
for (Octree<T> child : children) {
if (child.remove(point, player)) {
return true;
}
}
return false;
}
public List<T> queryRange(BoundingBox range) {
List<T> found = new ArrayList<>();
if (!boundary.intersects(range)) {
return found;
}
for (Entry entry : points) {
if (range.contains(entry.position)) {
found.add(entry.data);
}
}
if (isDivided) {
for (Octree<T> child : children) {
found.addAll(child.queryRange(range));
}
}
return found;
}
private void subdivide() {
double x = boundary.center.x;
double y = boundary.center.y;
double z = boundary.center.z;
double newHalfSize = boundary.halfSize / 2.0;
children = new Octree[8];
children[0] = new Octree<>(new BoundingBox(new Point3D(x - newHalfSize, y - newHalfSize, z - newHalfSize), newHalfSize));
children[1] = new Octree<>(new BoundingBox(new Point3D(x + newHalfSize, y - newHalfSize, z - newHalfSize), newHalfSize));
children[2] = new Octree<>(new BoundingBox(new Point3D(x - newHalfSize, y + newHalfSize, z - newHalfSize), newHalfSize));
children[3] = new Octree<>(new BoundingBox(new Point3D(x + newHalfSize, y + newHalfSize, z - newHalfSize), newHalfSize));
children[4] = new Octree<>(new BoundingBox(new Point3D(x - newHalfSize, y - newHalfSize, z + newHalfSize), newHalfSize));
children[5] = new Octree<>(new BoundingBox(new Point3D(x + newHalfSize, y - newHalfSize, z + newHalfSize), newHalfSize));
children[6] = new Octree<>(new BoundingBox(new Point3D(x - newHalfSize, y + newHalfSize, z + newHalfSize), newHalfSize));
children[7] = new Octree<>(new BoundingBox(new Point3D(x + newHalfSize, y + newHalfSize, z + newHalfSize), newHalfSize));
isDivided = true;
}
public static class Point3D {
double x, y, z;
public Point3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
}
public static class BoundingBox {
Point3D center;
double halfSize;
public BoundingBox(Point3D center, double halfSize) {
this.center = center;
this.halfSize = halfSize;
}
public boolean contains(Point3D point) {
return Math.abs(point.x - center.x) <= halfSize &&
Math.abs(point.y - center.y) <= halfSize &&
Math.abs(point.z - center.z) <= halfSize;
}
public boolean intersects(BoundingBox other) {
return Math.abs(center.x - other.center.x) <= halfSize + other.halfSize &&
Math.abs(center.y - other.center.y) <= halfSize + other.halfSize &&
Math.abs(center.z - other.center.z) <= halfSize + other.halfSize;
}
}
private class Entry {
Point3D position;
T data;
Entry(Point3D position, T data) {
this.position = position;
this.data = data;
}
}
}

View File

@@ -1,105 +0,0 @@
package com.hibiscusmc.hmccosmetics.util;
import com.hibiscusmc.hmccosmetics.HMCCosmeticsPlugin;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class PlayerSearchManager implements Listener {
private final Map<UUID, Octree<Player>> worldOctrees = new HashMap<>();
private final Map<UUID, Octree.Point3D> playerPositions = new HashMap<>();
//private static final double WORLD_HALF_SIZE = 30_000_000; // Previous built in value
private final double WORLD_HALF_SIZE;
public PlayerSearchManager(@NotNull HMCCosmeticsPlugin plugin) {
WORLD_HALF_SIZE = (double) plugin.getServer().getMaxWorldSize() / 2;
}
private Octree<Player> getOrCreateOctree(World world) {
return worldOctrees.computeIfAbsent(world.getUID(), $ -> {
Octree.BoundingBox worldBoundary = new Octree.BoundingBox(
new Octree.Point3D(0, 160, 0), WORLD_HALF_SIZE
);
return new Octree<>(worldBoundary);
});
}
private Octree.Point3D toPoint3D(Location location) {
return new Octree.Point3D(location.getX(), location.getY(), location.getZ());
}
public boolean addPlayer(Player player) {
Octree<Player> octree = getOrCreateOctree(player.getWorld());
Octree.Point3D point = toPoint3D(player.getLocation());
if(octree.insert(point, player)) {
playerPositions.put(player.getUniqueId(), point);
return true;
}
return false;
}
public boolean removePlayer(Player player) {
Octree<Player> octree = worldOctrees.get(player.getWorld().getUID());
if (octree == null) return false;
Octree.Point3D point = playerPositions.remove(player.getUniqueId());
if (point != null) return octree.remove(point, player);
return false;
}
public void updatePlayerPosition(Player player) {
removePlayer(player);
addPlayer(player);
}
public List<Player> getPlayersInRange(Location location, double range) {
Octree<Player> octree = worldOctrees.get(location.getWorld().getUID());
if (octree == null) return Collections.emptyList();
Octree.Point3D point = toPoint3D(location);
Octree.BoundingBox searchArea = new Octree.BoundingBox(point, range);
return octree.queryRange(searchArea)
.stream()
.filter(Objects::nonNull)
.toList();
}
public void clear() {
worldOctrees.clear();
playerPositions.clear();
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent event) {
if (event.hasChangedBlock()) updatePlayerPosition(event.getPlayer());
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
updatePlayerPosition(event.getPlayer());
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerQuit(PlayerQuitEvent event) {
removePlayer(event.getPlayer());
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerJoin(PlayerJoinEvent event) {
addPlayer(event.getPlayer());
}
}

View File

@@ -1,5 +1,6 @@
package com.hibiscusmc.hmccosmetics.util; package com.hibiscusmc.hmccosmetics.util;
import me.lojosho.hibiscuscommons.util.StringUtils;
import me.lojosho.shaded.configurate.ConfigurationNode; import me.lojosho.shaded.configurate.ConfigurationNode;
import java.util.ArrayList; import java.util.ArrayList;
@@ -31,7 +32,7 @@ public class TranslationUtil {
public static String getTranslation(String key, String message) { public static String getTranslation(String key, String message) {
List<TranslationPair> pairs = keys.get(key); List<TranslationPair> pairs = keys.get(key);
for (TranslationPair pair : pairs) { for (TranslationPair pair : pairs) {
if (pair.key().equals(message)) return pair.value(); if (pair.key().equals(message)) return StringUtils.parseStringToString(pair.value());
} }
return message; return message;

View File

@@ -1,19 +1,17 @@
package com.hibiscusmc.hmccosmetics.util.packets; package com.hibiscusmc.hmccosmetics.util.packets;
import com.google.common.collect.Lists;
import com.hibiscusmc.hmccosmetics.config.Settings; import com.hibiscusmc.hmccosmetics.config.Settings;
import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot; import com.hibiscusmc.hmccosmetics.cosmetic.CosmeticSlot;
import com.hibiscusmc.hmccosmetics.user.CosmeticUser; import com.hibiscusmc.hmccosmetics.user.CosmeticUser;
import com.hibiscusmc.hmccosmetics.user.CosmeticUsers; import com.hibiscusmc.hmccosmetics.user.CosmeticUsers;
import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils; import com.hibiscusmc.hmccosmetics.util.HMCCInventoryUtils;
import me.lojosho.hibiscuscommons.nms.MinecraftVersion; import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.packets.PacketManager; import me.lojosho.hibiscuscommons.util.packets.PacketManager;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Display; import org.bukkit.entity.*;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -27,7 +25,6 @@ import java.util.UUID;
public class HMCCPacketManager extends PacketManager { public class HMCCPacketManager extends PacketManager {
// The cloud effect map, in case it gets lost: Map<Integer, Number> dataValues = Map.of(0, (byte) 0x20, 8, 0f);
private static final List<CosmeticSlot> EQUIPMENT_SLOTS = List.of(CosmeticSlot.HELMET, CosmeticSlot.CHESTPLATE, CosmeticSlot.LEGGINGS, CosmeticSlot.BOOTS, CosmeticSlot.MAINHAND, CosmeticSlot.OFFHAND); private static final List<CosmeticSlot> EQUIPMENT_SLOTS = List.of(CosmeticSlot.HELMET, CosmeticSlot.CHESTPLATE, CosmeticSlot.LEGGINGS, CosmeticSlot.BOOTS, CosmeticSlot.MAINHAND, CosmeticSlot.OFFHAND);
public static void sendEntitySpawnPacket( public static void sendEntitySpawnPacket(
@@ -88,55 +85,20 @@ public class HMCCPacketManager extends PacketManager {
equipmentSlotUpdate(entityId, HMCCInventoryUtils.getEquipmentSlot(cosmeticSlot), user.getUserCosmeticItem(cosmeticSlot), sendTo); equipmentSlotUpdate(entityId, HMCCInventoryUtils.getEquipmentSlot(cosmeticSlot), user.getUserCosmeticItem(cosmeticSlot), sendTo);
} }
public static void sendInvisibilityPacket( public static void sendArmorstandMetadata(int entityId, List<Player> sendTo) {
int entityId, // 0x21 = Invisible + Fire (Aka, burns to make it not take the light of the block its in, avoiding turning it black)
List<Player> sendTo byte mask = (byte) (Settings.isBackpackPreventDarkness() ? 0x21 : 0x20);
) {
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, Map.of(0, (byte) 0x20), sendTo);
}
public static void spawnCloudAndHandleEffect(
int entityId,
Location location,
UUID uuid,
List<Player> sendTo
) {
NMSHandlers.getHandler().getPacketHandler().sendInvisibleParticleCloud(entityId, location, uuid, sendTo);
}
/**
* This handles both spawn + metadata in a bundle packet
* @param entityId
* @param location
* @param uuid
* @param sendTo
*/
public static void spawnInvisibleArmorstand(
int entityId,
Location location,
UUID uuid,
List<Player> sendTo
) {
byte mask = getMask();
NMSHandlers.getHandler().getPacketHandler().sendInvisibleArmorstand(entityId, location, uuid, mask, sendTo);
}
/**
* This is just a normal meta data packet (non-bundled)
* @param entityId
* @param sendTo
*/
public static void sendArmorstandMetadata(
int entityId,
List<Player> sendTo
) {
byte mask = getMask();
Map<Integer, Number> dataValues = Map.of(0, mask, 15, (byte) 0x10); Map<Integer, Number> dataValues = Map.of(0, mask, 15, (byte) 0x10);
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, dataValues, sendTo); NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, dataValues, sendTo);
} }
private static byte getMask() { public static void sendInvisibilityPacket(int entityId, List<Player> sendTo) {
return (byte) (Settings.isBackpackPreventDarkness() ? 0x21 : 0x20); NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, Map.of(0, (byte) 0x20), sendTo);
}
public static void sendCloudEffect(int entityId, List<Player> sendTo) {
Map<Integer, Number> dataValues = Map.of(0, (byte) 0x20, 8, 0f);
NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(entityId, dataValues, sendTo);
} }
public static void sendRotationPacket( public static void sendRotationPacket(
@@ -153,7 +115,11 @@ public class HMCCPacketManager extends PacketManager {
boolean onGround, boolean onGround,
@NotNull List<Player> sendTo @NotNull List<Player> sendTo
) { ) {
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, location.getYaw(), location.getPitch(), onGround, sendTo); float ROTATION_FACTOR = 256.0F / 360.0F;
byte yaw = (byte) (location.getYaw() * ROTATION_FACTOR);
byte pitch = (byte) (location.getPitch() * ROTATION_FACTOR);
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw, pitch, onGround, sendTo);
} }
public static void sendRotationPacket( public static void sendRotationPacket(
@@ -162,9 +128,11 @@ public class HMCCPacketManager extends PacketManager {
boolean onGround, boolean onGround,
@NotNull List<Player> sendTo @NotNull List<Player> sendTo
) { ) {
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw, 0, onGround, sendTo); float ROTATION_FACTOR = 256.0F / 360.0F;
NMSHandlers.getHandler().getPacketHandler().sendRotationPacket(entityId, yaw * ROTATION_FACTOR, 0, onGround, sendTo);
} }
/** /**
* Mostly to deal with backpacks, this deals with entities riding other entities. * Mostly to deal with backpacks, this deals with entities riding other entities.
* @param mountId The entity that is the "mount", ex. a player * @param mountId The entity that is the "mount", ex. a player
@@ -206,6 +174,22 @@ public class HMCCPacketManager extends PacketManager {
sendRidingPacket(mountId, new int[] {passengerId}, sendTo); sendRidingPacket(mountId, new int[] {passengerId}, sendTo);
} }
/**
*
* @param location Location of the fake player.
* @param uuid UUID of the fake player. Should be random.
* @param entityId The entityID that the entity will take on.
* @param sendTo Who should it send the packet to?
*/
public static void sendFakePlayerSpawnPacket(
final @NotNull Location location,
final UUID uuid,
final int entityId,
final @NotNull List<Player> sendTo
) {
sendEntitySpawnPacket(location, entityId, EntityType.PLAYER, uuid, sendTo);
}
/** /**
* Creates a fake player entity. * Creates a fake player entity.
* @param skinnedPlayer The original player it bases itself off of. * @param skinnedPlayer The original player it bases itself off of.
@@ -231,21 +215,28 @@ public class HMCCPacketManager extends PacketManager {
final int playerId, final int playerId,
final @NotNull List<Player> sendTo final @NotNull List<Player> sendTo
) { ) {
// https://minecraft.wiki/w/Java_Edition_protocol/Entity_metadata#Avatar /*
0x01 = Is on fire
0x02 = Is courching
0x04 = Unusued
0x08 = Sprinting
0x10 = Is swimming
0x20 = Invisibile
0x40 = Is Glowing
0x80 = Is flying with an elytra
https://wiki.vg/Entity_metadata#Entity
*/
final byte mask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x40; final byte mask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x40;
if (NMSHandlers.getVersion().isLowerOrEqual(MinecraftVersion.v1_21_8)) NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(playerId, Map.of(17, mask), sendTo); NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(playerId, Map.of(17, mask), sendTo);
else NMSHandlers.getHandler().getPacketHandler().sendSharedEntityData(playerId, Map.of(16, mask), sendTo);
} }
/** /**
* Removes a fake player from being seen by players. * Removes a fake player from being seen by players.
* @param player Which gameprofile to wrap for removing the player.
* @param uuid What is the fake player UUID * @param uuid What is the fake player UUID
* @param sendTo Whom to send the packet to * @param sendTo Whom to send the packet to
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void sendRemovePlayerPacket( public static void sendRemovePlayerPacket(
final Player player,
final UUID uuid, final UUID uuid,
final List<Player> sendTo final List<Player> sendTo
) { ) {
@@ -278,19 +269,7 @@ public class HMCCPacketManager extends PacketManager {
NMSHandlers.getHandler().getPacketHandler().sendMovePacket(entityId, from, to, onGround, sendTo); NMSHandlers.getHandler().getPacketHandler().sendMovePacket(entityId, from, to, onGround, sendTo);
} }
public static void sendEntityScalePacket( public static void sendDisplayEntityMetadataPacket(int entityid, ItemStack backpackItem, List<Player> sendTo) {
int entityId,
double scale,
List<Player> sendTo
) {
NMSHandlers.getHandler().getPacketHandler().sendEntityScalePacket(entityId, scale, sendTo);
}
// For future transition to display entities
public static void sendDisplayEntityMetadataPacket(
int entityid,
ItemStack backpackItem,
List<Player> sendTo) {
// TODO: Make the default values adjustable // TODO: Make the default values adjustable
Vector3f translation = new Vector3f(0, 3, 0); Vector3f translation = new Vector3f(0, 3, 0);
Vector3f scale = new Vector3f(1, 1, 1); Vector3f scale = new Vector3f(1, 1, 1);

View File

@@ -3,42 +3,32 @@
# #
config-version: 1 config-version: 1
default-menu: defaultmenu_hats default-menu: defaultmenu
debug-mode: false debug-mode: false
database-settings: database-settings:
# SQLite (Default), MYSQL, NONE type: sqlite # SQLite (Default), MYSQL, NONE
type: sqlite
mysql: mysql:
database: "database" database: database
password: "cherryBomb" password: cherryBomb
port: 3306 port: 3306
host: "localhost" host: localhost
user: "username" user: username
delay: delay:
# This is for if other plugins need to handle certain aspects of a player first. enabled: false # This is for if other plugins need to handle certain aspects of a player first.
enabled: false delay: 20 # In ticks
# Delay in ticks from when a player joins
delay: 20
cosmetic-settings: cosmetic-settings:
# In ticks, determines how many times a player cosmetics should be updated. -1 to disable. tick-period: 20 # In ticks, determines how many times a player cosmetics should be updated. -1 to disable.
# Ticking periods is something that ensures new players near a player get the packets to actually apply to the user. # Ticking periods is something that ensures new players near a player get the packets to actually apply to the user.
tick-period: 20
# If when a player dies, their cosmetics should be unapplied. If this is true, use hmccosmetics.unapplydeath.bypass to bypass unapply-on-death: false # If when a player dies, their cosmetics should be unapplied. If this is true, use hmccosmetics.unapplydeath.bypass to bypass
unapply-on-death: false force-permission-join: true # Checks a player permission if they can have a cosmetic when they join the server.
# Checks a player permission if they can have a cosmetic when they join the server. force-show-join: false # If the plugin should force show a player's cosmetics when they join the server.
force-permission-join: true
# If the plugin should attempt to force show a player's cosmetics when they join the server by removing all hidden flags.
force-show-join: false
# This determines what to process what areas to process placeholders when displaying the item to the user. # This determines what to process what areas to process placeholders when displaying the item to the user.
# This can be heavy on servers with a lot of players, so if experiencing lag issues relating to setting display/lores of items, disable this. # This can be heavy on servers with a lot of players, so if experiencing lag issues relating to setting display/lores of items, disable this.
item-processing: item-processing:
display-name: false display-name: true
lore: false lore: true
# This prevents the offhand from being swapped with the mainhand. Only affects if a user has a cosmetic in their offhand
offhand-prevent-swapping: false
# This is a list of worlds that cosmetics are hidden in. When a player enters one of these worlds, their cosmetics will be hidden. # This is a list of worlds that cosmetics are hidden in. When a player enters one of these worlds, their cosmetics will be hidden.
disabled-worlds: disabled-worlds:
@@ -51,9 +41,13 @@ cosmetic-settings:
- "SPECTATOR" - "SPECTATOR"
# 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. # 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: true backpack-force-riding-packet: false
# This prevents the backpack from being dark when the player is below a block at the expense of making the backpack bright # This prevents the backpack from being dark when the player is below a block at the expense of making the backpack bright
backpack-prevent-darkness: true backpack-prevent-darkness: 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.
slot-options: slot-options:
helmet: helmet:
@@ -91,7 +85,6 @@ cosmetic-settings:
x: 0.5 x: 0.5
y: 3 y: 3
z: 0.5 z: 0.5
menu-settings: menu-settings:
click-cooldown: click-cooldown:
enabled: true enabled: true
@@ -103,23 +96,23 @@ menu-settings:
# The shading is done through the title and by shifting textures around. This is done by offsets. # The shading is done through the title and by shifting textures around. This is done by offsets.
# Only Nexo is support by default. Vanilla can't properly handle it without a lot of unicodes and ItemsAdder adds weird offsets and decolors it. (This is why it is disabled by default) # Only Nexo is support by default. Vanilla can't properly handle it without a lot of unicodes and ItemsAdder adds weird offsets and decolors it. (This is why it is disabled by default)
enabled: false # Default of menus having shading. This can be toggled individually in menus with "shading: true/false" enabled: false # Default of menus having shading. This can be toggled individually in menus with "shading: true/false"
first-row-shift: "<shift:-153>" # Nexo: "<shift:-153>" first-row-shift: "<shift:-169>" # Nexo: "<shift:-169>"
sequent-row-shift: " <shift:-153>" # Nexo: " <shift:-153>" (Space is important here!) sequent-row-shift: " <shift:-169>" # Nexo: " <shift:-169>" (Space is important here!)
individual-column-shift: "<shift:-3>" # Nexo: "<shift:-3>" individual-column-shift: "<shift:-3>" # Nexo: "<shift:-3>"
background: "<glyph:hmcc_shade_row_<row>:colorable> " # Nexo: "<glyph:shade_row_<row>:colorable> background: "<glyph:shade_row_<row>:colorable> " # Nexo: "<glyph:shade_row_<row>:colorable>
clear-background: "<glyph:hmcc_clear_row_<row>:colorable> " # Nexo: "<glyph:clear_row_<row>:colorable> " clear-background: "<glyph:clear_row_<row>:colorable> " # Nexo: "<glyph:clear_row_<row>:colorable> "
#These use MiniMessage for color! https://docs.advntr.dev/minimessage/format.html#color #These use MiniMessage for color! https://docs.advntr.dev/minimessage/format.html#color
equipped-cosmetic-color: "<yellow>" equipped-cosmetic-color: "<yellow>"
equipable-cosmetic-color: "<green>" equipable-cosmetic-color: "<green>"
locked-cosmetic-color: "<red>" locked-cosmetic-color: "<red>"
cosmetic-type: cosmetic-type:
# This allows you to specify if it should require a special click type for the interaction to work. # This allows you to specify if it should require a special click type for the interaction to work.
equip-click: "ANY" # ANY or ClickType, https://jd.papermc.io/paper/org/bukkit/event/inventory/ClickType.html 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/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: dye-menu:
# If you use ItemsAdder, set this to "<white>:img_offset_-8::img_hmcc_dye_menu:" # 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:hmcc_dye_menu>" # If you use Oraxen, set this to "<white><s:-8><g:dye_menu>"
# If you use Nexo, set this to "<white><shift:-8><glyph:hmcc_dye_menu>" # If you use Nexo, set this to "<white><shift:-8><glyph:dye_menu>"
title: "<white>" title: "<white>"
input-slot: 10 input-slot: 10
output-slot: 16 output-slot: 16
@@ -129,8 +122,7 @@ hook-settings:
# could cause console spam as HMCCosmetics has to reload itself as well. # could cause console spam as HMCCosmetics has to reload itself as well.
reload-on-change: false reload-on-change: false
nexo: nexo:
# This causes the plugin to reload itself after any Nexo change. This keeps the plugin fully up to date with Nexo, but # This causes the plugin to reload itself after any Nexo change. This keeps the plugin fully up to date with Nexo
# could cause console spam as HMCCosmetics has to reload itself as well.
reload-on-change: true reload-on-change: true
worldguard: worldguard:
# Checks worldguard regions for HMCC flags. If set to false, flags will not work properly. # Checks worldguard regions for HMCC flags. If set to false, flags will not work properly.
@@ -178,10 +170,8 @@ wardrobe:
title-fade-out: 1000 # milliseconds title-fade-out: 1000 # milliseconds
wardrobes: wardrobes:
default: default:
# Distance in blocks that a player can interact with the wardrobe. -1 to ignore. distance: -1 # Distance in blocks that a player can interact with the wardrobe. -1 to ignore.
distance: -1 permission: "hmccosmetics.wardrobe.default" # Permission required to use the wardrobe.
# Permission required to use the wardrobe.
permission: "hmccosmetics.wardrobe.default"
default-menu: defaultmenu default-menu: defaultmenu
npc-location: npc-location:
world: "world" world: "world"

View File

@@ -0,0 +1,180 @@
title: "<white>"
rows: 6
refresh-rate: 20 # Set to -1 or remove to disable auto-updating, leading to it only using event-based updates.
items:
beanie:
slots:
- 0
item:
material: hmccosmetics:beanie
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_beanie%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_beanie%"
type: cosmetic
cosmetic: beanie
backpack:
slots:
- 1
item:
material: hmccosmetics:backpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_backpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_backpack%"
type: cosmetic
cosmetic: backpack
future_wings:
slots:
- 2
item:
material: hmccosmetics:future_wings
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_future_wings%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_future_wings%"
type: cosmetic
cosmetic: future_wings
lantern_cosmetic:
slots:
- 3
item:
material: hmccosmetics:lantern_cosmetic
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_lantern_cosmetic%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_lantern_cosmetic%"
type: cosmetic
cosmetic: lantern_cosmetic
baseball_hat:
slots:
- 4
item:
material: hmccosmetics:baseball_hat
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_baseball_hat%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_baseball_hat%"
type: cosmetic
cosmetic: baseball_hat
frog_hat:
slots:
- 5
item:
material: hmccosmetics:frog_hat
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_frog_hat%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_frog_hat%"
type: cosmetic
cosmetic: frog_hat
jetpack:
slots:
- 6
item:
material: hmccosmetics:jetpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_jetpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_jetpack%"
type: cosmetic
cosmetic: jetpack
hammer:
slots:
- 7
item:
material: hmccosmetics:hammer
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_hammer%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_hammer%"
type: cosmetic
cosmetic: hammer
chestplate:
slots:
- 8
item:
material: hmccosmetics:chestplate
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_chestplate%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_chestplate%"
type: cosmetic
cosmetic: chestplate
pants:
slots:
- 9
item:
material: hmccosmetics:pants
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_pants%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_pants%"
type: cosmetic
cosmetic: pants
boots:
slots:
- 10
item:
material: hmccosmetics:boots
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_boots%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_boots%"
type: cosmetic
cosmetic: boots
kite:
slots:
- 11
item:
material: hmccosmetics:kite
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_kite%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_kite%"
type: cosmetic
cosmetic: kite
explorer_backpack:
slots:
- 12
item:
material: hmccosmetics:explorer_backpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_explorer_backpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_explorer_backpack%"
type: cosmetic
cosmetic: explorer_backpack
garbage_truck_balloon:
slots:
- 13
item:
material: hmccosmetics:garbage_truck_balloon
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_garbage_truck_balloon%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_garbage_truck_balloon%"
type: cosmetic
cosmetic: garbage_truck_balloon
earth_day_grabber:
slots:
- 14
item:
material: hmccosmetics:earth_day_grabber
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_earth_day_grabber%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_earth_day_grabber%"
type: cosmetic
cosmetic: earth_day_grabber
hibiscus_flower:
slots:
- 15
item:
material: hmccosmetics:hibiscus_flower
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_hibiscus_flower%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_hibiscus_flower%"
type: cosmetic
cosmetic: hibiscus_flower

View File

@@ -1,99 +0,0 @@
title: "<white>"
rows: 6
items:
backpack:
slots:
- 1
item:
material: hmccosmetics:backpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_backpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_backpack%"
type: cosmetic
cosmetic: backpack
future_wings:
slots:
- 2
item:
material: hmccosmetics:future_wings
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_future_wings%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_future_wings%"
type: cosmetic
cosmetic: future_wings
jetpack:
slots:
- 3
item:
material: hmccosmetics:jetpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_jetpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_jetpack%"
type: cosmetic
cosmetic: jetpack
explorer_backpack:
slots:
- 4
item:
material: hmccosmetics:explorer_backpack
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_explorer_backpack%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_explorer_backpack%"
type: cosmetic
cosmetic: explorer_backpack
button_backpacks_menu:
slots:
- 0
item:
material: PAPER
model-data: 18
name: "<blue>Backpack Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_backpacks"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hand_menu:
slots:
- 18
item:
material: PAPER
model-data: 19
name: "<blue>Hand Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hands"
- "[SOUND] minecraft:ui.button.click 1 1"
button_balloon_menu:
slots:
- 27
item:
material: PAPER
model-data: 20
name: "<blue>Balloon Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_balloons"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hats_menu:
slots:
- 36
item:
material: PAPER
model-data: 17
name: "<blue>Hat Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hats"
- "[SOUND] minecraft:ui.button.click 1 1"

View File

@@ -1,77 +0,0 @@
title: "<white>"
rows: 6
items:
garbage_truck_balloon:
slots:
- 1
item:
material: hmccosmetics:garbage_truck_balloon
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_garbage_truck_balloon%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_garbage_truck_balloon%"
type: cosmetic
cosmetic: garbage_truck_balloon
kite:
slots:
- 2
item:
material: hmccosmetics:kite
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_kite%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_kite%"
type: cosmetic
cosmetic: kite
button_backpacks_menu:
slots:
- 27
item:
material: PAPER
model-data: 18
name: "<blue>Backpack Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_backpacks"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hand_menu:
slots:
- 36
item:
material: PAPER
model-data: 19
name: "<blue>Hand Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hands"
- "[SOUND] minecraft:ui.button.click 1 1"
button_balloon_menu:
slots:
- 0
item:
material: PAPER
model-data: 20
name: "<blue>Balloon Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_balloons"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hats_menu:
slots:
- 18
item:
material: PAPER
model-data: 17
name: "<blue>Hat Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hats"
- "[SOUND] minecraft:ui.button.click 1 1"

View File

@@ -1,99 +0,0 @@
title: "<white>"
rows: 6
items:
lantern_cosmetic:
slots:
- 1
item:
material: hmccosmetics:lantern_cosmetic
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_lantern_cosmetic%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_lantern_cosmetic%"
type: cosmetic
cosmetic: lantern_cosmetic
hammer:
slots:
- 2
item:
material: hmccosmetics:hammer
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_hammer%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_hammer%"
type: cosmetic
cosmetic: hammer
earth_day_grabber:
slots:
- 3
item:
material: hmccosmetics:earth_day_grabber
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_earth_day_grabber%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_earth_day_grabber%"
type: cosmetic
cosmetic: earth_day_grabber
hibiscus_flower:
slots:
- 4
item:
material: hmccosmetics:hibiscus_flower
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_hibiscus_flower%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_hibiscus_flower%"
type: cosmetic
cosmetic: hibiscus_flower
button_backpacks_menu:
slots:
- 36
item:
material: PAPER
model-data: 18
name: "<blue>Backpack Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_backpacks"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hand_menu:
slots:
- 0
item:
material: PAPER
model-data: 19
name: "<blue>Hand Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hands"
- "[SOUND] minecraft:ui.button.click 1 1"
button_balloon_menu:
slots:
- 18
item:
material: PAPER
model-data: 20
name: "<blue>Balloon Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_balloons"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hats_menu:
slots:
- 27
item:
material: PAPER
model-data: 17
name: "<blue>Hat Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hats"
- "[SOUND] minecraft:ui.button.click 1 1"

View File

@@ -1,88 +0,0 @@
title: "<white>"
rows: 6
items:
beanie:
slots:
- 1
item:
material: hmccosmetics:beanie
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_beanie%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_beanie%"
type: cosmetic
cosmetic: beanie
baseball_hat:
slots:
- 2
item:
material: hmccosmetics:baseball_hat
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_baseball_hat%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_baseball_hat%"
type: cosmetic
cosmetic: baseball_hat
frog_hat:
slots:
- 3
item:
material: hmccosmetics:frog_hat
lore:
- ""
- "<gray>Enabled: <#6D9DC5>%HMCCosmetics_equipped_frog_hat%"
- "<gray>Allowed: <#6D9DC5>%HMCCosmetics_unlocked_frog_hat%"
type: cosmetic
cosmetic: frog_hat
button_hats_menu:
slots:
- 0
item:
material: PAPER
model-data: 17
name: "<blue>Hat Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hats"
- "[SOUND] minecraft:ui.button.click 1 1"
button_backpacks_menu:
slots:
- 18
item:
material: PAPER
model-data: 18
name: "<blue>Backpack Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_backpacks"
- "[SOUND] minecraft:ui.button.click 1 1"
button_hand_menu:
slots:
- 27
item:
material: PAPER
model-data: 19
name: "<blue>Hand Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_hands"
- "[SOUND] minecraft:ui.button.click 1 1"
button_balloon_menu:
slots:
- 36
item:
material: PAPER
model-data: 20
name: "<blue>Balloon Cosmetics"
amount: 1
type: empty
actions:
any:
- "[MENU] defaultmenu_balloons"
- "[SOUND] minecraft:ui.button.click 1 1"

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME