diff --git a/.gitignore b/.gitignore index 58bc0397..87ea6ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -122,7 +122,6 @@ run/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle/wrapper/gradle-wrapper.jar -!**/libs/*.jar CLAUDE.md .claude updates.md diff --git a/API/build.gradle.kts b/API/build.gradle.kts index 1299e914..886f75e6 100644 --- a/API/build.gradle.kts +++ b/API/build.gradle.kts @@ -8,7 +8,6 @@ rootProject.extra.properties["sha"]?.let { sha -> dependencies { compileOnly(libs.paper.api) - compileOnly(files("../libs/zMenu-1.1.2.0.jar")) implementation(libs.sarah) implementation(libs.folialib) diff --git a/API/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java b/API/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java index c7900886..31b3abf1 100644 --- a/API/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java +++ b/API/src/main/java/fr/maxlego08/essentials/api/EssentialsPlugin.java @@ -101,9 +101,16 @@ public interface EssentialsPlugin extends Plugin { ModuleManager getModuleManager(); /** - * Gets the inventory manager for managing inventories. - * - * @return The inventory manager. + * Gets the inventory manager provided by the required zMenu plugin. + *

+ * In addition to inventories, zMenu 1.1.2.1 and later expose item serialization and + * sound creation through this service. Its item serializer preserves the format + * used by existing zEssentials mailbox, vault and item hologram data. + * + * @return The registered zMenu inventory manager. + * @see InventoryManager#serializeItemStack(org.bukkit.inventory.ItemStack) + * @see InventoryManager#deserializeItemStack(String) + * @see InventoryManager#createSoundOption(String, String, float, float) */ InventoryManager getInventoryManager(); diff --git a/API/src/main/java/fr/maxlego08/essentials/api/mailbox/MailBoxItem.java b/API/src/main/java/fr/maxlego08/essentials/api/mailbox/MailBoxItem.java index 785b8b9c..a3951917 100644 --- a/API/src/main/java/fr/maxlego08/essentials/api/mailbox/MailBoxItem.java +++ b/API/src/main/java/fr/maxlego08/essentials/api/mailbox/MailBoxItem.java @@ -1,7 +1,8 @@ package fr.maxlego08.essentials.api.mailbox; import fr.maxlego08.essentials.api.dto.MailBoxDTO; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; +import fr.maxlego08.menu.api.InventoryManager; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import java.util.Date; @@ -31,14 +32,21 @@ public MailBoxItem(UUID uuid, ItemStack itemStack, Date expiredAt) { } /** - * Constructs a new MailBoxItem from a MailBoxDTO. + * Restores a mailbox item from its stored data using zMenu's item serializer. + *

+ * Requires zMenu 1.1.2.1 or later to be enabled and its {@link InventoryManager} + * service to be registered. The stored item format remains compatible with + * mailbox entries saved before the API migration. * * @param mailBoxDTO the data transfer object containing mailbox item data + * @throws NullPointerException if the DTO is null or the inventory manager service is unavailable + * @see InventoryManager#deserializeItemStack(String) */ public MailBoxItem(MailBoxDTO mailBoxDTO) { this.id = mailBoxDTO.id(); this.uuid = mailBoxDTO.unique_id(); - this.itemStack = ItemStackUtils.deserializeItemStack(mailBoxDTO.itemstack()); + InventoryManager inventoryManager = Bukkit.getServicesManager().load(InventoryManager.class); + this.itemStack = inventoryManager.deserializeItemStack(mailBoxDTO.itemstack()); this.expiredAt = mailBoxDTO.expired_at(); } @@ -72,7 +80,7 @@ public UUID getUniqueId() { /** * Gets the item stack stored in the mailbox. * - * @return the item stack + * @return the stored item, or null if no item was stored or deserialization failed */ public ItemStack getItemStack() { return itemStack; diff --git a/build.gradle.kts b/build.gradle.kts index bd674ed0..4f2944c8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -75,8 +75,6 @@ allprojects { dependencies { compileOnly(rootLibs.zmenu.api) - // Still needed for item persistence and sound helpers not exposed by the zMenu API. - compileOnly(files("libs/zMenu-1.1.2.0.jar")) compileOnly(rootLibs.sarah) compileOnly(rootLibs.folialib) diff --git a/changelog.md b/changelog.md index 3f97dc45..2132a481 100644 --- a/changelog.md +++ b/changelog.md @@ -34,7 +34,7 @@ - `/enchant` now uses server registry identifiers, including datapack and plugin enchantments; legacy API methods remain available and deprecated - Unified item lookup and suggestions for give, mailbox and vault commands; feedback uses translated item names and preserves custom names - Fixed custom item delivery to offline mail recipients and stale custom items after reloads -- Use the published zMenu **1.1.2.0** API for skulls and kit conversion/saving; the local JAR remains required for item persistence and sound helpers +- Require zMenu **1.1.2.1** and use its published API for items and sounds; removed the local zMenu JAR while preserving stored items and custom resource-pack sounds - Migrated messages and configuration examples to native MiniMessage hex colors, including scoreboard animations; existing files must replace legacy `&`, `ยง` and bare hex color codes - Fixed MiniMessage text serialization, italic formatting and bold text alignment, and preserved click events with Adventure `5.x` - Fixed feedback placeholders, duplicate Death Message registration, version comparisons and incomplete downloads; existing `command-enchant-error-enchant` messages must use `%enchant%` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2986087a..cf2f4b12 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ mysql-connector = "26.10.0" mariadb-connector = "3.5.6" # Integration Hooks -zmenu-api = "1.1.2.0" +zmenu-api = "1.1.2.1" placeholderapi = "2.12.3" blocktracker = "1.0.6" mythicmobs = "5.7.2" diff --git a/libs/zMenu-1.1.2.0.jar b/libs/zMenu-1.1.2.0.jar deleted file mode 100644 index d364e61c..00000000 Binary files a/libs/zMenu-1.1.2.0.jar and /dev/null differ diff --git a/src/main/java/fr/maxlego08/essentials/commands/commands/vault/CommandVaultGetSlot.java b/src/main/java/fr/maxlego08/essentials/commands/commands/vault/CommandVaultGetSlot.java index 36b66f82..6130ae81 100644 --- a/src/main/java/fr/maxlego08/essentials/commands/commands/vault/CommandVaultGetSlot.java +++ b/src/main/java/fr/maxlego08/essentials/commands/commands/vault/CommandVaultGetSlot.java @@ -7,7 +7,6 @@ import fr.maxlego08.essentials.api.messages.Message; import fr.maxlego08.essentials.module.modules.vault.VaultModule; import fr.maxlego08.essentials.zutils.utils.commands.VCommand; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -51,7 +50,7 @@ protected CommandResultType perform(EssentialsPlugin plugin) { } VaultItemDTO vaultItemDTO = optional.get(); - ItemStack itemStack = ItemStackUtils.deserializeItemStack(vaultItemDTO.item()); + ItemStack itemStack = plugin.getInventoryManager().deserializeItemStack(vaultItemDTO.item()); String itemName = itemStack == null ? "unknown" : getItemName(itemStack); message(this.sender, Message.COMMAND_VAULT_GET_SLOT_SUCCESS, "%player%", playerName, "%vault%", vaultId, "%slot%", slot, "%amount%", String.valueOf(vaultItemDTO.quantity()), "%item%", itemName); diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java b/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java index 5392e80c..c2c189f8 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/TeleportationModule.java @@ -8,9 +8,8 @@ import fr.maxlego08.essentials.api.teleportation.WorldOverride; import fr.maxlego08.essentials.api.user.User; import fr.maxlego08.essentials.module.ZModule; +import fr.maxlego08.essentials.zutils.utils.CustomSoundOption; import fr.maxlego08.menu.api.sound.SoundOption; -import fr.maxlego08.menu.hooks.xseries.XSound; -import fr.maxlego08.menu.sound.ZSoundOption; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -24,7 +23,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Optional; import java.util.Queue; import java.util.Random; import java.util.UUID; @@ -96,15 +94,22 @@ private SoundOption loadSoundOption(YamlConfiguration configuration, String path float volume = (float) section.getDouble("volume", 1.0); float pitch = (float) section.getDouble("pitch", 1.0); - Optional xSound = XSound.of(soundName); - - return new ZSoundOption(xSound.orElse(null), "MASTER", soundName, pitch, volume, xSound.isEmpty()); + SoundOption soundOption = this.plugin.getInventoryManager().createSoundOption(soundName, "MASTER", pitch, volume); + return soundOption == null ? new CustomSoundOption(soundName, pitch, volume) : soundOption; } + /** + * @return the configured teleportation countdown sound, including custom resource-pack sounds, + * or null when this sound is disabled or unconfigured + */ public SoundOption getCountdownSound() { return countdownSound; } + /** + * @return the configured teleportation completion sound, including custom resource-pack sounds, + * or null when this sound is disabled or unconfigured + */ public SoundOption getCompleteSound() { return completeSound; } diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/chat/ChatModule.java b/src/main/java/fr/maxlego08/essentials/module/modules/chat/ChatModule.java index 5891cad2..46cf7cf8 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/chat/ChatModule.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/chat/ChatModule.java @@ -19,12 +19,11 @@ import fr.maxlego08.essentials.api.utils.DynamicCooldown; import fr.maxlego08.essentials.module.ZModule; import fr.maxlego08.essentials.storage.ConfigStorage; +import fr.maxlego08.essentials.zutils.utils.CustomSoundOption; import fr.maxlego08.essentials.zutils.utils.TimerBuilder; import fr.maxlego08.essentials.zutils.utils.paper.PaperComponent; import fr.maxlego08.menu.api.engine.Pagination; import fr.maxlego08.menu.api.sound.SoundOption; -import fr.maxlego08.menu.hooks.xseries.XSound; -import fr.maxlego08.menu.sound.ZSoundOption; import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -114,11 +113,11 @@ public void loadConfiguration() { this.chatDisplays.clear(); if (this.enablePing) { SoundOption pingSoundOption = null; - // Resolve the sound cross-version via XSound. Since Paper 1.21.3+ org.bukkit.Sound is an interface - // (no longer an enum), the reflection config loader can no longer map it, so we resolve it manually. if (this.enablePlayerPingSound && this.playerPingSound != null && !this.playerPingSound.isEmpty()) { - Optional xSound = XSound.of(this.playerPingSound); - pingSoundOption = new ZSoundOption(xSound.orElse(null), "MASTER", this.playerPingSound, this.playerPingSoundPitch, this.playerPingSoundVolume, xSound.isEmpty()); + pingSoundOption = this.plugin.getInventoryManager().createSoundOption(this.playerPingSound, "MASTER", this.playerPingSoundPitch, this.playerPingSoundVolume); + if (pingSoundOption == null) { + pingSoundOption = new CustomSoundOption(this.playerPingSound, this.playerPingSoundPitch, this.playerPingSoundVolume); + } } this.pingDisplay = new PlayerPingDisplay(this.plugin, this.playerPingColor, this.playerPingColorOther, pingSoundOption); } diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/hologram/HologramLoader.java b/src/main/java/fr/maxlego08/essentials/module/modules/hologram/HologramLoader.java index 5c90b289..b0c6e39f 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/hologram/HologramLoader.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/hologram/HologramLoader.java @@ -13,7 +13,6 @@ import fr.maxlego08.essentials.zutils.utils.ZUtils; import fr.maxlego08.menu.api.exceptions.InventoryException; import fr.maxlego08.menu.api.utils.Loader; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Material; @@ -90,7 +89,7 @@ private void loadConfiguration(YamlConfiguration configuration, HologramConfigur } private void loadItemConfiguration(YamlConfiguration configuration, ItemHologramConfiguration itemHologramConfiguration) { - itemHologramConfiguration.setItemStack(ItemStackUtils.deserializeItemStack(configuration.getString("itemstack", "null"))); + itemHologramConfiguration.setItemStack(this.plugin.getInventoryManager().deserializeItemStack(configuration.getString("itemstack", "null"))); } private void loadBlockConfiguration(YamlConfiguration configuration, BlockHologramConfiguration blockHologramConfiguration) { @@ -164,7 +163,7 @@ public void save(Hologram hologram, YamlConfiguration configuration, String path configuration.set("block-material", blockHologramConfiguration.getMaterial().name()); } else if (hologramConfiguration instanceof ItemHologramConfiguration itemHologramConfiguration) { - configuration.set("itemstack", ItemStackUtils.serializeItemStack(itemHologramConfiguration.getItemStack())); + configuration.set("itemstack", this.plugin.getInventoryManager().serializeItemStack(itemHologramConfiguration.getItemStack())); } } diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/vault/VaultModule.java b/src/main/java/fr/maxlego08/essentials/module/modules/vault/VaultModule.java index e158ef44..29c94a30 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/vault/VaultModule.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/vault/VaultModule.java @@ -14,7 +14,6 @@ import fr.maxlego08.essentials.api.vault.VaultResult; import fr.maxlego08.essentials.api.vault.VaultSlotType; import fr.maxlego08.essentials.module.ZModule; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -229,7 +228,7 @@ public VaultResult addNewItemToVault(Vault vault, UUID uniqueId, ItemStack curre VaultItem newVaultItem = new ZVaultItem(slot, currentItem, quantity); vault.getVaultItems().put(slot, newVaultItem); int finalSlot = slot; - getStorage().createVaultItem(uniqueId, vault.getVaultId(), finalSlot, newVaultItem.getQuantity(), ItemStackUtils.serializeItemStack(currentItem)); + getStorage().createVaultItem(uniqueId, vault.getVaultId(), finalSlot, newVaultItem.getQuantity(), this.plugin.getInventoryManager().serializeItemStack(currentItem)); return new VaultResult(vault, slot); } @@ -446,7 +445,7 @@ public boolean addItem(UUID uniqueId, ItemStack itemStack, long amount) { } VaultItem newVaultItem = new ZVaultItem(nextSlot, itemStack, amount); vault.getVaultItems().put(nextSlot, newVaultItem); - storage.createVaultItem(uniqueId, vault.getVaultId(), nextSlot, newVaultItem.getQuantity(), ItemStackUtils.serializeItemStack(itemStack)); + storage.createVaultItem(uniqueId, vault.getVaultId(), nextSlot, newVaultItem.getQuantity(), this.plugin.getInventoryManager().serializeItemStack(itemStack)); } return true; } diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZPlayerVaults.java b/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZPlayerVaults.java index 8c5543e1..057d7313 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZPlayerVaults.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZPlayerVaults.java @@ -5,7 +5,8 @@ import fr.maxlego08.essentials.api.vault.Vault; import fr.maxlego08.essentials.api.vault.VaultManager; import fr.maxlego08.essentials.zutils.utils.ZUtils; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; +import fr.maxlego08.menu.api.InventoryManager; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import java.util.HashMap; @@ -39,7 +40,8 @@ public Map getVaults() { @Override public void createVault(VaultDTO vaultDTO) { - this.vaults.put(vaultDTO.vault_id(), new ZVault(vaultDTO.unique_id(), vaultDTO.vault_id(), vaultDTO.name(), ItemStackUtils.deserializeItemStack(vaultDTO.icon()))); + InventoryManager inventoryManager = Bukkit.getServicesManager().load(InventoryManager.class); + this.vaults.put(vaultDTO.vault_id(), new ZVault(vaultDTO.unique_id(), vaultDTO.vault_id(), vaultDTO.name(), inventoryManager.deserializeItemStack(vaultDTO.icon()))); } @Override diff --git a/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZVault.java b/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZVault.java index c7e11c6c..3752692c 100644 --- a/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZVault.java +++ b/src/main/java/fr/maxlego08/essentials/module/modules/vault/ZVault.java @@ -4,7 +4,8 @@ import fr.maxlego08.essentials.api.vault.Vault; import fr.maxlego08.essentials.api.vault.VaultItem; import fr.maxlego08.essentials.zutils.utils.ZUtils; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; +import fr.maxlego08.menu.api.InventoryManager; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -70,7 +71,8 @@ public void setIconItemStack(ItemStack iconItemStack) { @Override public void createItem(VaultItemDTO vaultItemDTO) { - this.vaultItems.put(vaultItemDTO.slot(), new ZVaultItem(vaultItemDTO.slot(), ItemStackUtils.deserializeItemStack(vaultItemDTO.item()), vaultItemDTO.quantity())); + InventoryManager inventoryManager = Bukkit.getServicesManager().load(InventoryManager.class); + this.vaultItems.put(vaultItemDTO.slot(), new ZVaultItem(vaultItemDTO.slot(), inventoryManager.deserializeItemStack(vaultItemDTO.item()), vaultItemDTO.quantity())); } @Override diff --git a/src/main/java/fr/maxlego08/essentials/storage/database/repositeries/UserMailBoxRepository.java b/src/main/java/fr/maxlego08/essentials/storage/database/repositeries/UserMailBoxRepository.java index 752de05e..3a3aaf67 100644 --- a/src/main/java/fr/maxlego08/essentials/storage/database/repositeries/UserMailBoxRepository.java +++ b/src/main/java/fr/maxlego08/essentials/storage/database/repositeries/UserMailBoxRepository.java @@ -4,7 +4,6 @@ import fr.maxlego08.essentials.api.dto.MailBoxDTO; import fr.maxlego08.essentials.api.mailbox.MailBoxItem; import fr.maxlego08.essentials.storage.database.Repository; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; import fr.maxlego08.sarah.DatabaseConnection; import java.util.Date; @@ -23,7 +22,7 @@ public List select(UUID uuid) { public void insert(MailBoxItem mailBoxItem) { this.insert(table -> { table.uuid("unique_id", mailBoxItem.getUniqueId()); - table.string("itemstack", ItemStackUtils.serializeItemStack(mailBoxItem.getItemStack())); + table.string("itemstack", this.plugin.getInventoryManager().serializeItemStack(mailBoxItem.getItemStack())); table.object("expired_at", mailBoxItem.getExpiredAt()); }, mailBoxItem::setId); } diff --git a/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java b/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java index 30c08a8b..61105914 100644 --- a/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java +++ b/src/main/java/fr/maxlego08/essentials/storage/storages/SqlStorage.java @@ -28,7 +28,6 @@ import fr.maxlego08.essentials.user.ZUser; import fr.maxlego08.essentials.zutils.utils.StorageHelper; import fr.maxlego08.essentials.zutils.utils.TypeSafeCache; -import fr.maxlego08.menu.common.utils.nms.ItemStackUtils; import fr.maxlego08.sarah.*; import fr.maxlego08.sarah.database.DatabaseType; import fr.maxlego08.sarah.logger.JULogger; @@ -821,7 +820,7 @@ public List getPlayerVaultSlots() { @Override public void updateVault(UUID uniqueId, Vault vault) { - async(uniqueId, () -> with(VaultRepository.class).update(uniqueId, vault.getVaultId(), vault.getName(), vault.getIconItemStack() == null ? null : ItemStackUtils.serializeItemStack(vault.getIconItemStack()))); + async(uniqueId, () -> with(VaultRepository.class).update(uniqueId, vault.getVaultId(), vault.getName(), vault.getIconItemStack() == null ? null : this.plugin.getInventoryManager().serializeItemStack(vault.getIconItemStack()))); } @Override diff --git a/src/main/java/fr/maxlego08/essentials/zutils/utils/CustomSoundOption.java b/src/main/java/fr/maxlego08/essentials/zutils/utils/CustomSoundOption.java new file mode 100644 index 00000000..836cf62f --- /dev/null +++ b/src/main/java/fr/maxlego08/essentials/zutils/utils/CustomSoundOption.java @@ -0,0 +1,63 @@ +package fr.maxlego08.essentials.zutils.utils; + +import fr.maxlego08.menu.api.sound.SoundOption; +import fr.maxlego08.menu.hooks.xseries.XSound; +import org.bukkit.Location; +import org.bukkit.SoundCategory; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * A zMenu sound option for resource-pack keys that its sound factory cannot resolve. + *

+ * Playback uses the configured key directly through Paper. Player sounds use the + * {@code MASTER} category; sounds played at another entity are heard in its world. + * No vanilla {@link XSound} is associated with this option. + * + * @param soundName the resource-pack sound key, for example {@code mypack:teleport} + * @param pitch the playback pitch + * @param volume the playback volume + * @see fr.maxlego08.menu.api.InventoryManager#createSoundOption(String, String, float, float) + */ +public record CustomSoundOption(String soundName, float pitch, float volume) implements SoundOption { + + /** + * @return null because this option plays a custom key rather than a vanilla sound + */ + @Override + public @Nullable XSound getSound() { + return null; + } + + @Override + public float getPitch() { + return this.pitch; + } + + @Override + public float getVolume() { + return this.volume; + } + + @Override + public boolean isCustom() { + return true; + } + + @Override + public @NotNull String getSoundName() { + return this.soundName; + } + + @Override + public void play(@NotNull Entity entity) { + Location location = entity.getLocation(); + if (entity instanceof Player player) { + player.playSound(location, this.soundName, SoundCategory.MASTER, this.volume, this.pitch); + } else { + location.getWorld().playSound(location, this.soundName, this.volume, this.pitch); + } + } +}