mirror of
https://github.com/SPAWNRYS-ban/FUCK-CustomDiscs.git
synced 2025-12-10 05:19:43 +05:00
Merge pull request #100 from Athar42/main
Update to 1.21.8 + 2 new features
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id "com.gradleup.shadow" version "8.3.6"
|
||||
id "com.gradleup.shadow" version "8.3.8"
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
java_version=21
|
||||
|
||||
mp3spi_version=1.9.5.4
|
||||
|
||||
bukkit_api_version=1.21
|
||||
bukkit_version=1.21.7-R0.1-SNAPSHOT
|
||||
bukkit_version=1.21.8-R0.1-SNAPSHOT
|
||||
mod_id=customdiscsplugin
|
||||
|
||||
# Target an older API to make it compatible with older versions of Simple Voice Chat
|
||||
voicechat_api_version=2.3.3
|
||||
command_api_version=10.1.1
|
||||
voicechat_api_version=2.5.31
|
||||
command_api_version=10.1.2
|
||||
|
||||
plugin_version=4.5
|
||||
plugin_version=5.0
|
||||
maven_group=me.Navoei.customdiscsplugin
|
||||
archives_base_name=custom-discs
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Sun Aug 11 17:52:06 EDT 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
122
readme.md
122
readme.md
@@ -1,7 +1,17 @@
|
||||
# Custom Discs v4.5 for Paper 1.21.6 and 1.21.7
|
||||
# Custom Discs v5.0 for Paper 1.21.7 / 1.21.8
|
||||
|
||||
> ### ⚠️⚠️⚠️ READ THIS SECTION CAREFULLY! ⚠️⚠️⚠️
|
||||
> ### This version introduce some breaking changes and *require at least the build 9 of PaperMC 1.21.7*.
|
||||
> ### Any earlier version of PaperMC is not guaranteed to function and new features may not function at all!
|
||||
> ### ⚠️⚠️⚠️ Please also note that this new release requires you to delete the ```config.yml``` and ```lang.yml``` files (or update them with the new options).
|
||||
> ### ⚠️⚠️⚠️ Without this being done, you could experience issues with this plugin.
|
||||
|
||||
|
||||
## 🆘 NEW : You can now ask for support on this Discord server ➡️ https://discord.gg/YJpqruvZ97 (but you can still use the "[Issues](https://github.com/Navoei/CustomDiscs/issues)" report section of GitHub)
|
||||
|
||||
|
||||
A Paper fork of henkelmax's Audio Player. Special thanks to Athar42 for maintaining this plugin.
|
||||
- Play custom music discs using the Simple Voice Chat API. (The voice chat mod is required on the client and server.)
|
||||
- Play custom music discs, goat horns and player's head using the Simple Voice Chat API. (The voice chat mod is required on the client and server.)
|
||||
- Use ```/customdisc``` or ```/cd``` to view available commands.
|
||||
- Music files should go into ```plugins/CustomDiscs/musicdata/```
|
||||
- Music files must be in the ```.wav```, ```.flac```, or ```.mp3``` format.
|
||||
@@ -19,16 +29,34 @@ Permission Nodes (Required to run the commands. Playing discs does not require a
|
||||
- ```customdiscs.create``` to create a disc
|
||||
- ```customdiscs.download``` to download a file
|
||||
- ```customdiscs.range``` to set the range of the disc
|
||||
- ```customdiscs.horncooldown``` to set the cooldown (in ticks) for using the modified goat horn
|
||||
|
||||
Dependencies:
|
||||
- This plugin depends on the latest version of ProtocolLib available for your Paper version and SimpleVoiceChatBukkit (2.5.33 is recommended).
|
||||
- This plugin depends on the latest version of ProtocolLib available for your Paper version and SimpleVoiceChatBukkit (latest is recommended - at least version 2.5.31 required).
|
||||
|
||||
|
||||
https://user-images.githubusercontent.com/64107368/178426026-c454ac66-5133-4f3a-9af9-7f674e022423.mp4
|
||||
|
||||
Default Config.yml:
|
||||
```
|
||||
# [Music Disc Config]
|
||||
# [General CustomDiscs Config]
|
||||
|
||||
# The maximum download size in megabytes.
|
||||
max-download-size: 50
|
||||
|
||||
# The master volume of music discs from 0-1. (You can set values like 0.5 for 50% volume).
|
||||
music-disc-volume: 1
|
||||
|
||||
# Debug Mode - To display some more logging information and Stack Trace informations
|
||||
debugMode: false
|
||||
|
||||
# [Music Discs Config]
|
||||
|
||||
# Enable custom music discs.
|
||||
music-disc-enable: true
|
||||
|
||||
# Enable "Now playing" message for custom music discs.
|
||||
music-disc-playing-enable: true
|
||||
|
||||
# The distance from which music discs can be heard in blocks.
|
||||
music-disc-distance: 16
|
||||
@@ -36,41 +64,75 @@ music-disc-distance: 16
|
||||
# The max distance from which music discs can be heard in blocks.
|
||||
music-disc-max-distance: 256
|
||||
|
||||
# The master volume of music discs from 0-1. (You can set values like 0.5 for 50% volume).
|
||||
music-disc-volume: 1
|
||||
# [Goat Horns Config]
|
||||
|
||||
# The maximum download size in megabytes.
|
||||
max-download-size: 50
|
||||
# Enable custom goat horns.
|
||||
custom-horn-enable: true
|
||||
|
||||
#Custom Discs Help Page
|
||||
# Enable "Now playing" message for custom horns.
|
||||
custom-horn-playing-enable: true
|
||||
|
||||
# The distance from which custom horns can be heard in blocks.
|
||||
custom-horn-distance: 16
|
||||
|
||||
# The max distance from which custom horns can be heard in blocks.
|
||||
custom-horn-max-distance: 256
|
||||
|
||||
# The default cooldown time for horns in ticks from 1 to the max value of horn-max-cooldown (1 second is 20 ticks).
|
||||
horn-cooldown: 140
|
||||
|
||||
# The default max cooldown time for horns in ticks (1 second is 20 ticks).
|
||||
horn-max-cooldown: 6000
|
||||
|
||||
# [Player Heads Config]
|
||||
|
||||
# Enable custom player heads.
|
||||
custom-head-enable: true
|
||||
|
||||
# Enable "Now playing" message for player heads.
|
||||
custom-head-playing-enable: true
|
||||
|
||||
# The distance from which music discs can be heard in blocks.
|
||||
custom-head-distance: 16
|
||||
|
||||
# The max distance from which music discs can be heard in blocks.
|
||||
custom-head-max-distance: 256
|
||||
|
||||
|
||||
# [DO NOT EDIT BELOW THIS LINE - Help configuration]
|
||||
# Custom Discs Help Page
|
||||
help:
|
||||
- "&8-[&6CustomDiscs Help Page&8]-"
|
||||
- "&8-[&6CustomDiscs v5.0 - Help Page&8]-"
|
||||
- "&aAuthor&7: &6Navoei"
|
||||
- "&aContributors&7: &6alfw / &6Athar42"
|
||||
- "&aContributors&7: &6Athar42 / &6alfw"
|
||||
- "&fGit&0Hub&7: &9&ohttps://github.com/Navoei/CustomDiscs"
|
||||
- "&aDiscord&7: &9&ohttps://discord.gg/YJpqruvZ97"
|
||||
```
|
||||
|
||||
Default Lang.yml:
|
||||
```
|
||||
prefix: "&8[&6CustomDiscs&8]&r"
|
||||
no-permission: "&cYou do not have permission to execute this command."
|
||||
invalid-filename: "&cThis is an invalid filename!"
|
||||
no-disc-name-provided: "&cYou must provide a name for your disc."
|
||||
invalid-format: "&cFile must be in wav, flac, or mp3 format!"
|
||||
file-not-found: "&cFile not found!"
|
||||
invalid-arguments: "&cInvalid arguments. &7(&a%command_syntax%&7)"
|
||||
not-holding-disc: "&cYou must hold a disc in your main hand."
|
||||
create-filename: "&7Your filename is: &a\"%filename%\"."
|
||||
create-custom-name: "&7Your custom name is: &a\"%custom_name%\"."
|
||||
downloading-file: "&7Downloading file..."
|
||||
file-too-large: "&cThe file is larger than %max_download_size%MB."
|
||||
successful-download: "&aFile successfully downloaded to &7%file_path%&a."
|
||||
create-disc: "&aCreate a disc by doing &7/cd create %filename% \"Custom Lore\"&a."
|
||||
download-error: "&cAn error has occurred while downloading."
|
||||
now-playing: "&6Now playing: %song_name%"
|
||||
disc-converted: "&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &7JukeboxPlayableComponent&f."
|
||||
invalid-range: "&cYou need to chose a range between 1 and %range_value%"
|
||||
create-custom-range: "&7Your range is set to: &a\"%custom_range%\"."
|
||||
prefix: '&8[&6CustomDiscs&8]&r'
|
||||
invalid-filename: '&cThis is an invalid filename!'
|
||||
invalid-format: '&cFile must be in wav, flac, or mp3 format!'
|
||||
file-not-found: '&cFile not found!'
|
||||
not-holding-correct-item: '&cYou must either hold a disc, goat horn or player head in your main hand.'
|
||||
create-filename: '&7Your filename is: &a"%filename%".'
|
||||
create-custom-name: '&7Your custom name is: &a"%custom_name%".'
|
||||
downloading-file: '&7Downloading file...'
|
||||
file-too-large: '&cThe file is larger than %max_download_size%MB.'
|
||||
successful-download: '&aFile successfully downloaded to &7%file_path%&a.'
|
||||
create-disc: '&aCreate a disc by doing &7/cd create %filename% "Custom Lore"&a.'
|
||||
download-error: '&cAn error has occurred while downloading.'
|
||||
now-playing: '&6Now playing: %song_name%'
|
||||
disc-converted: '&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &7ToolTipDisplay&f.'
|
||||
invalid-range: '&cYou need to chose a range between 1 and %range_value%'
|
||||
create-custom-range: '&7Your range is set to: &a"%custom_range%".'
|
||||
not-holding-modified-goathorn: '&cYou must hold a modified goat horn in your main hand.'
|
||||
invalid-cooldown: '&cYou need to chose a cooldown between 1 and %cooldown_value% (in ticks)'
|
||||
create-custom-goat-cooldown: '&7Your goat horn cooldown is set to: &a"%custom_goat_cooldown%".'
|
||||
custom-music-disabled: '&7Custom music discs are disabled in the configuration.'
|
||||
custom-head-disabled: '&7Custom player heads are disabled in the configuration.'
|
||||
custom-horn-disabled: '&7Custom goat horns are disabled in the configuration.'
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package me.Navoei.customdiscsplugin;
|
||||
|
||||
import me.Navoei.customdiscsplugin.command.CustomDiscCommand;
|
||||
import me.Navoei.customdiscsplugin.event.JukeBox;
|
||||
import me.Navoei.customdiscsplugin.event.HeadPlay;
|
||||
import me.Navoei.customdiscsplugin.event.HornPlay;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
@@ -7,12 +13,12 @@ import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
|
||||
import de.maxhenkel.voicechat.api.BukkitVoicechatService;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPI;
|
||||
import dev.jorel.commandapi.CommandAPIBukkitConfig;
|
||||
import me.Navoei.customdiscsplugin.command.CustomDiscCommand;
|
||||
import me.Navoei.customdiscsplugin.event.JukeBox;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Jukebox;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@@ -30,23 +36,38 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
|
||||
@Nullable
|
||||
private VoicePlugin voicechatPlugin;
|
||||
private Logger log;
|
||||
private Logger pluginLogger;
|
||||
private static boolean debugMode = false;
|
||||
public static YamlConfiguration LANG;
|
||||
public static File LANG_FILE;
|
||||
public static boolean musicDiscEnable = true;
|
||||
public static boolean musicDiscPlayingEnable = true;
|
||||
public float musicDiscDistance;
|
||||
public float musicDiscMaxDistance;
|
||||
public float musicDiscVolume;
|
||||
public static boolean customHornEnable = true;
|
||||
public static boolean customHornPlayingEnable = true;
|
||||
public float customHornDistance;
|
||||
public float customHornMaxDistance;
|
||||
public int hornCooldown;
|
||||
public int hornMaxCooldown;
|
||||
public static boolean customHeadEnable = true;
|
||||
public static boolean customHeadPlayingEnable = true;
|
||||
public float customHeadDistance;
|
||||
public float customHeadMaxDistance;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
CustomDiscs.instance = this;
|
||||
CommandAPI.onLoad(new CommandAPIBukkitConfig(this).verboseOutput(true));
|
||||
//To get CommandAPI working on newer MC Release - for development
|
||||
//CommandAPI.onLoad(new CommandAPIBukkitConfig(this).verboseOutput(true).beLenientForMinorVersions(true));
|
||||
new CustomDiscCommand(this).register("customdiscs");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
log = getLogger();
|
||||
pluginLogger = getLogger();
|
||||
|
||||
CommandAPI.onEnable();
|
||||
|
||||
@@ -54,7 +75,29 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
|
||||
this.saveDefaultConfig();
|
||||
loadLang();
|
||||
|
||||
|
||||
// Config initializer section
|
||||
debugMode = getConfig().getBoolean("debugMode", false);
|
||||
musicDiscEnable = getConfig().getBoolean("music-disc-enable");
|
||||
musicDiscPlayingEnable = getConfig().getBoolean("music-disc-playing-enable");
|
||||
musicDiscDistance = getConfig().getInt("music-disc-distance");
|
||||
musicDiscMaxDistance = getConfig().getInt("music-disc-max-distance");
|
||||
musicDiscVolume = Float.parseFloat(Objects.requireNonNull(getConfig().getString("music-disc-volume")));
|
||||
customHornEnable = getConfig().getBoolean("custom-horn-enable");
|
||||
customHornPlayingEnable = getConfig().getBoolean("custom-horn-playing-enable");
|
||||
customHornDistance = getConfig().getInt("custom-horn-distance");
|
||||
customHornMaxDistance = getConfig().getInt("custom-horn-max-distance");
|
||||
hornCooldown = getConfig().getInt("horn-cooldown");
|
||||
hornMaxCooldown = getConfig().getInt("horn-max-cooldown");
|
||||
customHeadEnable = getConfig().getBoolean("custom-head-enable");
|
||||
customHeadPlayingEnable = getConfig().getBoolean("custom-head-playing-enable");
|
||||
customHeadDistance = getConfig().getInt("custom-head-distance");
|
||||
customHeadMaxDistance = getConfig().getInt("custom-head-max-distance");
|
||||
|
||||
// Checking server version and display console message in case the server is not supported
|
||||
ServerVersionChecker serverVersionChecker = new ServerVersionChecker(this);
|
||||
serverVersionChecker.checkVersion();
|
||||
|
||||
File musicData = new File(this.getDataFolder(), "musicdata");
|
||||
if (!(musicData.exists())) {
|
||||
musicData.mkdirs();
|
||||
@@ -63,26 +106,36 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
if (service != null) {
|
||||
voicechatPlugin = new VoicePlugin();
|
||||
service.registerPlugin(voicechatPlugin);
|
||||
log.info("Successfully registered CustomDiscs plugin");
|
||||
pluginLogger.info("Successfully registered CustomDiscs plugin");
|
||||
} else {
|
||||
log.info("Failed to register CustomDiscs plugin");
|
||||
pluginLogger.info("Failed to register CustomDiscs plugin");
|
||||
}
|
||||
|
||||
getServer().getPluginManager().registerEvents(new JukeBox(), this);
|
||||
getServer().getPluginManager().registerEvents(new HopperManager(), this);
|
||||
|
||||
musicDiscDistance = Objects.requireNonNull(getConfig().getInt("music-disc-distance"));
|
||||
musicDiscMaxDistance = Objects.requireNonNull(getConfig().getInt("music-disc-max-distance"));
|
||||
musicDiscVolume = Float.parseFloat(Objects.requireNonNull(getConfig().getString("music-disc-volume")));
|
||||
|
||||
|
||||
if (isMusicDiscEnable()) {
|
||||
getServer().getPluginManager().registerEvents(new JukeBox(), this);
|
||||
getServer().getPluginManager().registerEvents(new HopperManager(), this);
|
||||
}
|
||||
if (isCustomHeadEnable()) { getServer().getPluginManager().registerEvents(new HeadPlay(), this); }
|
||||
if (isCustomHornEnable()) { getServer().getPluginManager().registerEvents(new HornPlay(), this); }
|
||||
|
||||
// To avoid any "0" values, set it to 1.
|
||||
if (hornCooldown <= 0) {
|
||||
hornCooldown = 1;
|
||||
}
|
||||
if (hornMaxCooldown <= 0) {
|
||||
hornMaxCooldown = 1;
|
||||
}
|
||||
|
||||
|
||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
protocolManager.addPacketListener(new PacketAdapter(this, ListenerPriority.NORMAL, PacketType.Play.Server.WORLD_EVENT) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
PacketContainer packet = event.getPacket();
|
||||
|
||||
|
||||
if (packet.getIntegers().read(0).toString().equals("1010")) {
|
||||
if (!isMusicDiscEnable()) { return; }
|
||||
Jukebox jukebox = (Jukebox) packet.getBlockPositionModifier().read(0).toLocation(event.getPlayer().getWorld()).getBlock().getState();
|
||||
|
||||
if (!jukebox.getRecord().hasItemMeta()) return;
|
||||
@@ -106,7 +159,7 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
CommandAPI.onDisable();
|
||||
if (voicechatPlugin != null) {
|
||||
getServer().getServicesManager().unregister(voicechatPlugin);
|
||||
log.info("Successfully unregistered CustomDiscs plugin");
|
||||
pluginLogger.info("Successfully unregistered CustomDiscs plugin");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +169,6 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* Load the lang.yml file.
|
||||
*
|
||||
* @return The lang.yml config.
|
||||
*/
|
||||
public void loadLang() {
|
||||
File lang = new File(getDataFolder(), "lang.yml");
|
||||
@@ -133,10 +184,12 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
Lang.setFile(defConfig);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // So they notice
|
||||
log.severe("Failed to create lang.yml for CustomDiscs.");
|
||||
log.severe("Now disabling...");
|
||||
pluginLogger.severe("Failed to create lang.yml for CustomDiscs.");
|
||||
pluginLogger.severe("Now disabling...");
|
||||
this.setEnabled(false); // Without it loaded, we can't send them messages
|
||||
if (isDebugMode()) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
YamlConfiguration conf = YamlConfiguration.loadConfiguration(lang);
|
||||
@@ -151,9 +204,11 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
try {
|
||||
conf.save(getLangFile());
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to save lang.yml for CustomDiscs");
|
||||
log.log(Level.WARNING, "Now disabling...");
|
||||
e.printStackTrace();
|
||||
pluginLogger.warning("Failed to save lang.yml for CustomDiscs");
|
||||
pluginLogger.warning("Now disabling...");
|
||||
if (isDebugMode()) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,8 +235,59 @@ public final class CustomDiscs extends JavaPlugin {
|
||||
try (OutputStream output = new FileOutputStream(file)) {
|
||||
input.transferTo(output);
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
if (isDebugMode()) {
|
||||
CustomDiscs.getInstance().getLogger().log(Level.SEVERE, "Exception output: ", ioException);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the debugMode configuration.
|
||||
*
|
||||
* @return The boolean value of debugMode.
|
||||
*/
|
||||
public static boolean isDebugMode() { return debugMode; }
|
||||
|
||||
/**
|
||||
* Get the musicDiscPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of musicDiscPlayingEnable.
|
||||
*/
|
||||
public static boolean isMusicDiscEnable() { return musicDiscEnable; }
|
||||
|
||||
/**
|
||||
* Get the customHornPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of customHornPlayingEnable.
|
||||
*/
|
||||
public static boolean isCustomHornEnable() { return customHornEnable; }
|
||||
|
||||
/**
|
||||
* Get the customHeadPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of customHeadPlayingEnable.
|
||||
*/
|
||||
public static boolean isCustomHeadEnable() { return customHeadEnable; }
|
||||
|
||||
/**
|
||||
* Get the musicDiscPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of musicDiscPlayingEnable.
|
||||
*/
|
||||
public static boolean isMusicDiscPlayingEnable() { return musicDiscPlayingEnable; }
|
||||
|
||||
/**
|
||||
* Get the customHornPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of customHornPlayingEnable.
|
||||
*/
|
||||
public static boolean isCustomHornPlayingEnable() { return customHornPlayingEnable; }
|
||||
|
||||
/**
|
||||
* Get the customHeadPlayingEnable configuration.
|
||||
*
|
||||
* @return The boolean value of customHeadPlayingEnable.
|
||||
*/
|
||||
public static boolean isCustomHeadPlayingEnable() { return customHeadPlayingEnable; }
|
||||
}
|
||||
@@ -1,54 +1,49 @@
|
||||
package me.Navoei.customdiscsplugin;
|
||||
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.TooltipDisplay;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import org.bukkit.block.BlockState;
|
||||
//import org.bukkit.block.Container;
|
||||
import org.bukkit.block.Jukebox;
|
||||
import org.bukkit.entity.minecart.HopperMinecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.components.JukeboxPlayableComponent;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.entity.minecart.HopperMinecart;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
|
||||
// Used only if logger is needed
|
||||
//import java.util.logging.Logger;
|
||||
//import org.bukkit.Bukkit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class HopperManager implements Listener {
|
||||
|
||||
CustomDiscs customDiscs = CustomDiscs.getInstance();
|
||||
|
||||
PlayerManager playerManager = PlayerManager.instance();
|
||||
|
||||
//private static final Logger logger = Bukkit.getLogger(); // or Logger.getLogger("Minecraft");
|
||||
private final Logger pluginLogger = customDiscs.getLogger();
|
||||
private final boolean debugModeResult = CustomDiscs.isDebugMode();
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onJukeboxInsertFromHopper(InventoryMoveItemEvent event) {
|
||||
//logger.warning("Enter : onJukeboxInsertFromHopper");
|
||||
if (debugModeResult) {
|
||||
pluginLogger.info("DEBUG - HopperManager -> Enter : onJukeboxInsertFromHopper");
|
||||
}
|
||||
if (event.getDestination().getLocation() == null) return;
|
||||
if (!event.getDestination().getType().equals(InventoryType.JUKEBOX)) return;
|
||||
if (!isCustomMusicDisc(event.getItem())) return;
|
||||
if (!TypeChecker.isCustomMusicDisc(event.getItem())) return;
|
||||
|
||||
Component songNameComponent = Objects.requireNonNull(event.getItem().getItemMeta().lore()).get(0).asComponent();
|
||||
String songName = PlainTextComponentSerializer.plainText().serialize(songNameComponent);
|
||||
@@ -78,7 +73,9 @@ public class HopperManager implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onJukeboxEjectToHopperMinecart(InventoryMoveItemEvent event) {
|
||||
//logger.warning("Enter : onJukeboxEjectToHopper");
|
||||
if (debugModeResult) {
|
||||
pluginLogger.info("DEBUG - HopperManager -> Enter : onJukeboxEjectToHopper");
|
||||
}
|
||||
|
||||
InventoryHolder holderSource = event.getSource().getHolder();
|
||||
InventoryHolder holderDestination = event.getDestination().getHolder();
|
||||
@@ -86,55 +83,39 @@ public class HopperManager implements Listener {
|
||||
if (event.getSource().getLocation() == null) return;
|
||||
if (!event.getSource().getType().equals(InventoryType.JUKEBOX)) return;
|
||||
if (event.getItem().getItemMeta() == null) return;
|
||||
if (!isCustomMusicDisc(event.getItem())) return;
|
||||
if (!TypeChecker.isCustomMusicDisc(event.getItem())) return;
|
||||
|
||||
if (holderDestination instanceof HopperMinecart) {
|
||||
stopDisc(((BlockState) holderSource).getBlock());
|
||||
playerManager.stopDisc(((BlockState) holderSource).getBlock());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
//logger.warning("Enter : onChunkLoad");
|
||||
if (debugModeResult) {
|
||||
pluginLogger.info("DEBUG - HopperManager -> Enter : onChunkLoad");
|
||||
}
|
||||
for (BlockState blockState : event.getChunk().getTileEntities()) {
|
||||
if (blockState instanceof Jukebox jukebox) {
|
||||
if (!jukebox.hasRecord()) return;
|
||||
if (!PlayerManager.instance().isAudioPlayerPlaying(blockState.getLocation()) && isCustomMusicDisc(jukebox.getRecord())) {
|
||||
//Set the block type to force an update.
|
||||
if (!PlayerManager.instance().isAudioPlayerPlaying(blockState.getLocation()) && TypeChecker.isCustomMusicDisc(jukebox.getRecord())) {
|
||||
jukebox.stopPlaying();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void discToHopper(Block block) {
|
||||
if (block == null) return;
|
||||
if (!block.getLocation().getChunk().isLoaded()) return;
|
||||
if (!block.getType().equals(Material.JUKEBOX)) return;
|
||||
|
||||
Jukebox jukebox = (Jukebox) block.getState();
|
||||
jukebox.stopPlaying();
|
||||
}
|
||||
|
||||
private boolean isCustomMusicDisc(ItemStack item) {
|
||||
//logger.warning("Enter : isCustomMusicDisc");
|
||||
return item.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customdisc"), PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
private void stopDisc(Block block) {
|
||||
playerManager.stopLocationalAudio(block.getLocation());
|
||||
}
|
||||
|
||||
private static HopperManager instance;
|
||||
|
||||
public static HopperManager instance() {
|
||||
//logger.warning("Enter : HopperManager Instance");
|
||||
if (CustomDiscs.isDebugMode()) {
|
||||
CustomDiscs.getInstance().getLogger().info("DEBUG - HopperManager -> Enter : HopperManager Instance");
|
||||
}
|
||||
if (instance == null) {
|
||||
instance = new HopperManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,4 +28,4 @@ public class JukeboxStateManager {
|
||||
}, 1, 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,29 @@
|
||||
package me.Navoei.customdiscsplugin;
|
||||
|
||||
import de.maxhenkel.voicechat.api.ServerPlayer;
|
||||
import de.maxhenkel.voicechat.api.VoicechatConnection;
|
||||
import de.maxhenkel.voicechat.api.VoicechatServerApi;
|
||||
import de.maxhenkel.voicechat.api.audiochannel.AudioChannel;
|
||||
import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer;
|
||||
import de.maxhenkel.voicechat.api.audiochannel.LocationalAudioChannel;
|
||||
|
||||
import javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider;
|
||||
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import org.jflac.sound.spi.Flac2PcmAudioInputStream;
|
||||
import org.jflac.sound.spi.FlacAudioFileReader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.sound.sampled.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -31,6 +32,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PlayerManager {
|
||||
|
||||
@@ -38,6 +41,11 @@ public class PlayerManager {
|
||||
private final Map<UUID, PlayerReference> playerMap;
|
||||
private final ExecutorService executorService;
|
||||
private static final AudioFormat FORMAT = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 48000F, 16, 1, 2, 48000F, false);
|
||||
private final Logger pluginLogger = plugin.getLogger();
|
||||
private final boolean debugModeResult = CustomDiscs.isDebugMode();
|
||||
private final boolean musicDiscPlayingEnableResult = CustomDiscs.isMusicDiscPlayingEnable();
|
||||
private final boolean customHornPlayingEnableResult = CustomDiscs.isCustomHornPlayingEnable();
|
||||
private final boolean customHeadPlayingEnableResult = CustomDiscs.isCustomHeadPlayingEnable();
|
||||
|
||||
public PlayerManager() {
|
||||
this.playerMap = new ConcurrentHashMap<>();
|
||||
@@ -60,9 +68,11 @@ public class PlayerManager {
|
||||
|
||||
Collection<ServerPlayer> playersInRange = api.getPlayersInRange(api.fromServerLevel(block.getWorld()), audioChannel.getLocation(), range);
|
||||
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
bukkitPlayer.sendActionBar(actionbarComponent);
|
||||
if (musicDiscPlayingEnableResult) {
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
bukkitPlayer.sendActionBar(actionbarComponent);
|
||||
}
|
||||
}
|
||||
|
||||
AtomicBoolean stopped = new AtomicBoolean();
|
||||
@@ -99,7 +109,142 @@ public class PlayerManager {
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//plugin.getServer().getRegionScheduler().run(plugin, block.getLocation(), scheduledTask -> HopperManager.instance().discToHopper(block));
|
||||
if (playerMap.containsValue(playerReference)) {
|
||||
playerMap.remove(id);
|
||||
}
|
||||
});
|
||||
synchronized (stopped) {
|
||||
if (!stopped.get()) {
|
||||
player.set(audioPlayer);
|
||||
} else {
|
||||
audioPlayer.stopPlaying();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void playAudioHorn(VoicechatServerApi api, Path soundFilePath, Player block, Component actionbarComponent, float range) {
|
||||
UUID id = UUID.nameUUIDFromBytes(block.getLocation().toString().getBytes());
|
||||
|
||||
LocationalAudioChannel audioChannel = api.createLocationalAudioChannel(id, api.fromServerLevel(block.getWorld()), api.createPosition(block.getLocation().getX() + 0.5d, block.getLocation().getY() + 0.5d, block.getLocation().getZ() + 0.5d));
|
||||
|
||||
if (audioChannel == null) return;
|
||||
|
||||
audioChannel.setCategory(VoicePlugin.GOAT_HORN_CATEGORY);
|
||||
audioChannel.setDistance(range);
|
||||
|
||||
Collection<ServerPlayer> playersInRange = api.getPlayersInRange(api.fromServerLevel(block.getWorld()), audioChannel.getLocation(), range);
|
||||
|
||||
if (customHornPlayingEnableResult) {
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
bukkitPlayer.sendActionBar(actionbarComponent);
|
||||
}
|
||||
}
|
||||
|
||||
AtomicBoolean stopped = new AtomicBoolean();
|
||||
AtomicReference<de.maxhenkel.voicechat.api.audiochannel.AudioPlayer> player = new AtomicReference<>();
|
||||
PlayerReference playerReference = new PlayerReference(() -> {
|
||||
synchronized (stopped) {
|
||||
stopped.set(true);
|
||||
de.maxhenkel.voicechat.api.audiochannel.AudioPlayer audioPlayer = player.get();
|
||||
if (audioPlayer != null) {
|
||||
audioPlayer.stopPlaying();
|
||||
}
|
||||
}
|
||||
}, player, soundFilePath);
|
||||
|
||||
playerMap.put(id, playerReference);
|
||||
|
||||
executorService.execute(() -> {
|
||||
AudioPlayer audioPlayer = null;
|
||||
AudioInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = getAudioInputStream(soundFilePath, FORMAT);
|
||||
audioPlayer = playChannelHorn(api, audioChannel, block, inputStream, playersInRange);
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (audioPlayer == null) {
|
||||
playerMap.remove(id);
|
||||
return;
|
||||
}
|
||||
AudioInputStream finalInputStream = inputStream;
|
||||
audioPlayer.setOnStopped(() -> {
|
||||
try {
|
||||
finalInputStream.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (playerMap.containsValue(playerReference)) {
|
||||
playerMap.remove(id);
|
||||
}
|
||||
});
|
||||
synchronized (stopped) {
|
||||
if (!stopped.get()) {
|
||||
player.set(audioPlayer);
|
||||
} else {
|
||||
audioPlayer.stopPlaying();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void playAudioHead(VoicechatServerApi api, Path soundFilePath, Block block, Component actionbarComponent, float range) {
|
||||
UUID id = UUID.nameUUIDFromBytes(block.getLocation().toString().getBytes());
|
||||
|
||||
LocationalAudioChannel audioChannel = api.createLocationalAudioChannel(id, api.fromServerLevel(block.getWorld()), api.createPosition(block.getLocation().getX() + 0.5d, block.getLocation().getY() + 0.5d, block.getLocation().getZ() + 0.5d));
|
||||
|
||||
if (audioChannel == null) return;
|
||||
|
||||
audioChannel.setCategory(VoicePlugin.PLAYER_HEAD_CATEGORY);
|
||||
audioChannel.setDistance(range);
|
||||
|
||||
Collection<ServerPlayer> playersInRange = api.getPlayersInRange(api.fromServerLevel(block.getWorld()), audioChannel.getLocation(), range);
|
||||
|
||||
if (customHeadPlayingEnableResult) {
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
bukkitPlayer.sendActionBar(actionbarComponent);
|
||||
}
|
||||
}
|
||||
|
||||
AtomicBoolean stopped = new AtomicBoolean();
|
||||
AtomicReference<de.maxhenkel.voicechat.api.audiochannel.AudioPlayer> player = new AtomicReference<>();
|
||||
PlayerReference playerReference = new PlayerReference(() -> {
|
||||
synchronized (stopped) {
|
||||
stopped.set(true);
|
||||
de.maxhenkel.voicechat.api.audiochannel.AudioPlayer audioPlayer = player.get();
|
||||
if (audioPlayer != null) {
|
||||
audioPlayer.stopPlaying();
|
||||
}
|
||||
}
|
||||
}, player, soundFilePath);
|
||||
|
||||
playerMap.put(id, playerReference);
|
||||
|
||||
executorService.execute(() -> {
|
||||
AudioPlayer audioPlayer = null;
|
||||
AudioInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = getAudioInputStream(soundFilePath, FORMAT);
|
||||
audioPlayer = playChannelHead(api, audioChannel, block, inputStream, playersInRange);
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (audioPlayer == null) {
|
||||
playerMap.remove(id);
|
||||
return;
|
||||
}
|
||||
AudioInputStream finalInputStream = inputStream;
|
||||
audioPlayer.setOnStopped(() -> {
|
||||
try {
|
||||
finalInputStream.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (playerMap.containsValue(playerReference)) {
|
||||
playerMap.remove(id);
|
||||
}
|
||||
@@ -117,18 +262,66 @@ public class PlayerManager {
|
||||
|
||||
@Nullable
|
||||
private de.maxhenkel.voicechat.api.audiochannel.AudioPlayer playChannel(VoicechatServerApi api, AudioChannel audioChannel, Block block, AudioInputStream inputStream, Collection<ServerPlayer> playersInRange) throws UnsupportedAudioFileException, IOException {
|
||||
//short[] audio = readSoundFile(soundFilePath);
|
||||
AudioPlayer audioPlayer = api.createAudioPlayer(audioChannel, api.createEncoder(), () -> {
|
||||
try {
|
||||
return readSoundFile(inputStream);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().info("Error Occurred At: " + block.getLocation());
|
||||
pluginLogger.severe("An error did occur while trying to play a music disc!");
|
||||
pluginLogger.info("Error Occurred At: " + block.getLocation());
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
TextComponent textComponent = Component.text("An error has occurred while trying to play this disc.").color(NamedTextColor.RED);
|
||||
bukkitPlayer.sendMessage(textComponent);
|
||||
}
|
||||
e.printStackTrace();
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
audioPlayer.startPlaying();
|
||||
return audioPlayer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private de.maxhenkel.voicechat.api.audiochannel.AudioPlayer playChannelHorn(VoicechatServerApi api, AudioChannel audioChannel, Player block, AudioInputStream inputStream, Collection<ServerPlayer> playersInRange) throws UnsupportedAudioFileException, IOException {
|
||||
AudioPlayer audioPlayer = api.createAudioPlayer(audioChannel, api.createEncoder(), () -> {
|
||||
try {
|
||||
return readSoundFile(inputStream);
|
||||
} catch (Exception e) {
|
||||
pluginLogger.severe("An error did occur while trying to play a goat horn!");
|
||||
pluginLogger.info("Error Occurred At: " + block.getLocation());
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
TextComponent textComponent = Component.text("An error has occurred while trying to play this goat horn.").color(NamedTextColor.RED);
|
||||
bukkitPlayer.sendMessage(textComponent);
|
||||
}
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
audioPlayer.startPlaying();
|
||||
return audioPlayer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private de.maxhenkel.voicechat.api.audiochannel.AudioPlayer playChannelHead(VoicechatServerApi api, AudioChannel audioChannel, Block block, AudioInputStream inputStream, Collection<ServerPlayer> playersInRange) throws UnsupportedAudioFileException, IOException {
|
||||
AudioPlayer audioPlayer = api.createAudioPlayer(audioChannel, api.createEncoder(), () -> {
|
||||
try {
|
||||
return readSoundFile(inputStream);
|
||||
} catch (Exception e) {
|
||||
pluginLogger.severe("An error did occur while trying to play a player head!");
|
||||
pluginLogger.info("Error Occurred At: " + block.getLocation());
|
||||
for (ServerPlayer serverPlayer : playersInRange) {
|
||||
Player bukkitPlayer = (Player) serverPlayer.getPlayer();
|
||||
TextComponent textComponent = Component.text("An error has occurred while trying to play this player head.").color(NamedTextColor.RED);
|
||||
bukkitPlayer.sendMessage(textComponent);
|
||||
}
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@@ -222,10 +415,11 @@ public class PlayerManager {
|
||||
}
|
||||
}
|
||||
|
||||
//public static float getLengthSeconds(Path file) throws UnsupportedAudioFileException, IOException {
|
||||
// short[] audio = readSoundFile(file);
|
||||
// return (float) audio.length / FORMAT.getSampleRate();
|
||||
//}
|
||||
// DISABLED FOR NOW, MAY BE REUSED LATER IF WE DECIDE TO IMPLEMENT IT
|
||||
/*public static float getLengthSeconds(Path file) throws UnsupportedAudioFileException, IOException {
|
||||
short[] audio = readSoundFile(file);
|
||||
return (float) audio.length / FORMAT.getSampleRate();
|
||||
}*/
|
||||
|
||||
public boolean isAudioPlayerPlaying(Location blockLocation) {
|
||||
UUID id = UUID.nameUUIDFromBytes(blockLocation.toString().getBytes());
|
||||
@@ -241,6 +435,10 @@ public class PlayerManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void stopDisc(Block block) {
|
||||
this.stopLocationalAudio(block.getLocation());
|
||||
}
|
||||
|
||||
private static PlayerManager instance;
|
||||
|
||||
public static PlayerManager instance() {
|
||||
@@ -259,4 +457,4 @@ public class PlayerManager {
|
||||
Path soundFilePath) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package me.Navoei.customdiscsplugin;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ServerVersionChecker {
|
||||
private static final String REQUIRED_VERSION = "1.21.7-9"; // Set the PaperMC required version
|
||||
private final Logger pluginLogger;
|
||||
private final boolean debugModeResult = CustomDiscs.isDebugMode();
|
||||
|
||||
public ServerVersionChecker(JavaPlugin plugin) {
|
||||
this.pluginLogger = plugin.getLogger();
|
||||
}
|
||||
|
||||
public void checkVersion() {
|
||||
// Get the full server version message output
|
||||
String versionMessage = Bukkit.getVersionMessage();
|
||||
|
||||
if (versionMessage == null) {
|
||||
pluginLogger.severe("Unable to detect the running server version. Is this a supported PaperMC release?");
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract server type and version
|
||||
Matcher serverInfoExtracted = Pattern.compile("This server is running (\\S+) version (\\S+)").matcher(versionMessage);
|
||||
|
||||
if (serverInfoExtracted.find()) {
|
||||
String serverType = serverInfoExtracted.group(1); // Extract the server type (Should be "Paper", but can be forks like "Purpur", "Spigot", ...)
|
||||
String buildVersion = serverInfoExtracted.group(2); // Extract the full version info (For example : 1.21.7-9-main@5661fbb)
|
||||
|
||||
if(debugModeResult) {
|
||||
pluginLogger.info("DEBUG - Detected Server Type: " + serverType);
|
||||
pluginLogger.info("DEBUG - Server Full Version: " + versionMessage);
|
||||
}
|
||||
|
||||
// As we only officially support Paper, we look up for it specifically
|
||||
if ("paper".equalsIgnoreCase(serverType)) {
|
||||
String cleanVersion = cleanBuildVersion(buildVersion);
|
||||
if(debugModeResult) {
|
||||
pluginLogger.info("DEBUG - Extracted Version: " + cleanVersion);
|
||||
}
|
||||
|
||||
// We then perform a version comparison
|
||||
if (compareVersions(cleanVersion) < 0) {
|
||||
pluginLogger.severe("This Paper server version is unsupported. Please update to at least Paper " + REQUIRED_VERSION);
|
||||
} else {
|
||||
pluginLogger.info("Paper server version is supported.");
|
||||
}
|
||||
} else {
|
||||
// For Paper forks servers (mostly), log a severe message about non-support
|
||||
pluginLogger.severe(serverType + " server detected. No support will be made in case of issues!");
|
||||
}
|
||||
} else {
|
||||
pluginLogger.severe("Unable to read the server version. Is this a supported PaperMC release?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the version string to remove the non usefull part after the build number (like '-main@5661fbb').
|
||||
* The result is only the main version part (like '1.21.7-9').
|
||||
*/
|
||||
private static String cleanBuildVersion(String version) {
|
||||
String[] versionParts = version.split("-");
|
||||
return versionParts.length >= 2 ? versionParts[0] + "-" + versionParts[1] : version;
|
||||
}
|
||||
|
||||
private static int compareVersions(String runningVersion) {
|
||||
// We first start by separating the main version number from the build number
|
||||
String[] currentVersion = runningVersion.split("-");
|
||||
String[] requiredVersion = REQUIRED_VERSION.split("-");
|
||||
|
||||
// Then we compare the base version (sub-function to handle it)
|
||||
// If we are in the same main version, we pass to the next check, else we exit (-1 = older release ; 1 = newer release)
|
||||
int result = compareVersionParts(currentVersion[0], requiredVersion[0]);
|
||||
if (result != 0) return result;
|
||||
|
||||
// And finally, we compare the build number (only if we are at the same main base version, to ensure we get the minimal build)
|
||||
return Integer.compare(Integer.parseInt(currentVersion[1]), Integer.parseInt(requiredVersion[1]));
|
||||
}
|
||||
|
||||
private static int compareVersionParts(String currentVersionPart, String requiredVersionPart) {
|
||||
// We split each numbers into individual components (major (1), minor (21), and patch versions (7), so we can compare it one by one)
|
||||
String[] currentVersionArray = currentVersionPart.split("\\.");
|
||||
String[] requiredVersionArray = requiredVersionPart.split("\\.");
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int currentVersion = Integer.parseInt(currentVersionArray[i]);
|
||||
int requiredVersion = Integer.parseInt(requiredVersionArray[i]);
|
||||
|
||||
if (currentVersion < requiredVersion) return -1;
|
||||
if (currentVersion > requiredVersion) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
73
src/main/java/me/Navoei/customdiscsplugin/TypeChecker.java
Normal file
73
src/main/java/me/Navoei/customdiscsplugin/TypeChecker.java
Normal file
@@ -0,0 +1,73 @@
|
||||
package me.Navoei.customdiscsplugin;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public class TypeChecker {
|
||||
static CustomDiscs customDiscs = CustomDiscs.getInstance();
|
||||
|
||||
// Commented methods are kept for possible future checks usage.
|
||||
|
||||
// MUSIC DISCS
|
||||
|
||||
public static boolean isMusicDisc(ItemStack item) {
|
||||
return item.getType().toString().contains("MUSIC_DISC");
|
||||
}
|
||||
|
||||
/*public static boolean isMusicDiscPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("MUSIC_DISC");
|
||||
}*/
|
||||
|
||||
public static boolean isCustomMusicDisc(ItemStack itemStack) {
|
||||
if (itemStack == null) return false;
|
||||
if (itemStack.getItemMeta() == null) return false;
|
||||
return itemStack.getType().toString().contains("MUSIC_DISC") && itemStack.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customdisc"), PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
/*public static boolean isCustomMusicDiscPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("MUSIC_DISC") && p.getInventory().getItemInMainHand().getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customdisc"), PersistentDataType.STRING);
|
||||
}*/
|
||||
|
||||
// GOAT HORNS
|
||||
|
||||
/*public static boolean isGoatHorn(ItemStack item) {
|
||||
return item.getType().toString().contains("GOAT_HORN");
|
||||
}*/
|
||||
|
||||
public static boolean isGoatHornPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("GOAT_HORN");
|
||||
}
|
||||
|
||||
public static boolean isCustomGoatHorn(PlayerInteractEvent e) {
|
||||
if (e.getItem()==null) return false;
|
||||
return e.getItem().getType().toString().contains("GOAT_HORN") && e.getItem().getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customhorn"), PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
public static boolean isCustomGoatHornPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("GOAT_HORN") && p.getInventory().getItemInMainHand().getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customhorn"), PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
// PLAYER HEADS
|
||||
|
||||
/*public static boolean isHead(ItemStack item) {
|
||||
return item.getType().toString().contains("PLAYER_HEAD");
|
||||
}*/
|
||||
|
||||
public static boolean isHeadPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("PLAYER_HEAD");
|
||||
}
|
||||
|
||||
/*public static boolean isCustomHead(ItemStack itemStack) {
|
||||
if (itemStack == null) return false;
|
||||
if (itemStack.getItemMeta() == null) return false;
|
||||
return itemStack.getType().toString().contains("PLAYER_HEAD") && itemStack.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customhead"), PersistentDataType.STRING);
|
||||
}*/
|
||||
|
||||
public static boolean isCustomHeadPlayer(Player p) {
|
||||
return p.getInventory().getItemInMainHand().getType().toString().contains("PLAYER_HEAD") && p.getInventory().getItemInMainHand().getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customhead"), PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class VoicePlugin implements VoicechatPlugin {
|
||||
|
||||
@@ -31,6 +33,9 @@ public class VoicePlugin implements VoicechatPlugin {
|
||||
@Nullable
|
||||
public static VolumeCategory playerHeads;
|
||||
|
||||
private final Logger pluginLogger = CustomDiscs.getInstance().getLogger();
|
||||
private final boolean debugModeResult = CustomDiscs.isDebugMode();
|
||||
|
||||
/**
|
||||
* @return the unique ID for this voice chat plugin
|
||||
*/
|
||||
@@ -70,6 +75,22 @@ public class VoicePlugin implements VoicechatPlugin {
|
||||
.build();
|
||||
voicechatServerApi.registerVolumeCategory(musicDiscs);
|
||||
|
||||
goatHorns = voicechatServerApi.volumeCategoryBuilder()
|
||||
.setId(GOAT_HORN_CATEGORY)
|
||||
.setName("Goat Horns")
|
||||
.setDescription("The volume of goat horns")
|
||||
.setIcon(getGoatHornsIcon())
|
||||
.build();
|
||||
voicechatServerApi.registerVolumeCategory(goatHorns);
|
||||
|
||||
playerHeads = voicechatServerApi.volumeCategoryBuilder()
|
||||
.setId(PLAYER_HEAD_CATEGORY)
|
||||
.setName("Player Heads")
|
||||
.setDescription("The volume of player heads (on noteblock)")
|
||||
.setIcon(getPlayerHeadIcon())
|
||||
.build();
|
||||
voicechatServerApi.registerVolumeCategory(playerHeads);
|
||||
|
||||
}
|
||||
|
||||
private int[][] getMusicDiscIcon() {
|
||||
@@ -94,7 +115,70 @@ public class VoicePlugin implements VoicechatPlugin {
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
pluginLogger.severe("An error occurred while trying to set the Music Disc icon category.");
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int[][] getGoatHornsIcon() {
|
||||
try {
|
||||
Enumeration<URL> resources = CustomDiscs.getInstance().getClass().getClassLoader().getResources("goat_horn_category.png");
|
||||
|
||||
while (resources.hasMoreElements()) {
|
||||
BufferedImage bufferedImage = ImageIO.read(resources.nextElement().openStream());
|
||||
if (bufferedImage.getWidth() != 16) {
|
||||
continue;
|
||||
}
|
||||
if (bufferedImage.getHeight() != 16) {
|
||||
continue;
|
||||
}
|
||||
int[][] image = new int[16][16];
|
||||
for (int x = 0; x < bufferedImage.getWidth(); x++) {
|
||||
for (int y = 0; y < bufferedImage.getHeight(); y++) {
|
||||
image[x][y] = bufferedImage.getRGB(x, y);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
pluginLogger.severe("An error occurred while trying to set the Goat Horn icon category.");
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int[][] getPlayerHeadIcon() {
|
||||
try {
|
||||
Enumeration<URL> resources = CustomDiscs.getInstance().getClass().getClassLoader().getResources("player_head_category.png");
|
||||
|
||||
while (resources.hasMoreElements()) {
|
||||
BufferedImage bufferedImage = ImageIO.read(resources.nextElement().openStream());
|
||||
if (bufferedImage.getWidth() != 16) {
|
||||
continue;
|
||||
}
|
||||
if (bufferedImage.getHeight() != 16) {
|
||||
continue;
|
||||
}
|
||||
int[][] image = new int[16][16];
|
||||
for (int x = 0; x < bufferedImage.getWidth(); x++) {
|
||||
for (int y = 0; y < bufferedImage.getHeight(); y++) {
|
||||
image[x][y] = bufferedImage.getRGB(x, y);
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
pluginLogger.severe("An error occurred while trying to set the Player Head icon category.");
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package me.Navoei.customdiscsplugin.command;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.command.SubCommands.CreateSubCommand;
|
||||
import me.Navoei.customdiscsplugin.command.SubCommands.DownloadSubCommand;
|
||||
import me.Navoei.customdiscsplugin.command.SubCommands.SetHornCooldownSubCommand;
|
||||
import me.Navoei.customdiscsplugin.command.SubCommands.SetRangeSubCommand;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.CommandPermission;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -21,10 +26,12 @@ public class CustomDiscCommand extends CommandAPICommand {
|
||||
|
||||
this.withAliases("cd");
|
||||
this.withFullDescription("The custom discs command.");
|
||||
|
||||
this.withPermission(CommandPermission.NONE);
|
||||
|
||||
this.withSubcommand(new CreateSubCommand(plugin));
|
||||
this.withSubcommand(new DownloadSubCommand(plugin));
|
||||
this.withSubcommand(new SetRangeSubCommand(plugin));
|
||||
this.withSubcommand(new SetHornCooldownSubCommand(plugin));
|
||||
|
||||
this.executesPlayer(this::onCommandPlayer);
|
||||
this.executesConsole(this::onCommandConsole);
|
||||
@@ -43,4 +50,5 @@ public class CustomDiscCommand extends CommandAPICommand {
|
||||
executor.sendMessage(NamedTextColor.RED + "Only players can use this command : '"+arguments+"'!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,29 @@
|
||||
package me.Navoei.customdiscsplugin.command.SubCommands;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.TypeChecker;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
|
||||
import dev.jorel.commandapi.arguments.StringArgument;
|
||||
import dev.jorel.commandapi.arguments.TextArgument;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.TooltipDisplay;
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import io.papermc.paper.registry.keys.InstrumentKeys;
|
||||
import io.papermc.paper.registry.keys.SoundEventKeys;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -38,7 +48,8 @@ public class CreateSubCommand extends CommandAPICommand {
|
||||
|
||||
this.withFullDescription(NamedTextColor.GRAY + "Creates a custom music disc.");
|
||||
this.withUsage("/customdisc create <filename> \"Custom Lore\"");
|
||||
|
||||
this.withPermission("customdiscs.create");
|
||||
|
||||
this.withArguments(new StringArgument("filename").replaceSuggestions(ArgumentSuggestions.stringCollection((sender) -> {
|
||||
File musicDataFolder = new File(this.plugin.getDataFolder(), "musicdata");
|
||||
if (!musicDataFolder.isDirectory()) {
|
||||
@@ -62,18 +73,17 @@ public class CreateSubCommand extends CommandAPICommand {
|
||||
private int onCommandPlayer(Player player, CommandArguments arguments) {
|
||||
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
boolean resultIsMusicDisc = TypeChecker.isMusicDisc(item);
|
||||
boolean resultIsHorn = TypeChecker.isGoatHornPlayer(player);
|
||||
boolean resultIsHead = TypeChecker.isHeadPlayer(player);
|
||||
|
||||
if (!isMusicDisc(item)) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NOT_HOLDING_DISC.toString()));
|
||||
if (!resultIsMusicDisc && !resultIsHorn && !resultIsHead) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NOT_HOLDING_CORRECT_ITEM.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("customdiscs.create")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NO_PERMISSION.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Find file, if file not there then say "file not there"
|
||||
|
||||
|
||||
|
||||
String filename = Objects.requireNonNull(arguments.getByClass("filename", String.class));
|
||||
if (filename.contains("../")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_FILENAME.toString()));
|
||||
@@ -94,17 +104,60 @@ public class CreateSubCommand extends CommandAPICommand {
|
||||
|
||||
String song_name = Objects.requireNonNull(arguments.getByClass("song_name", String.class));
|
||||
|
||||
ItemStack disc = new ItemStack(player.getInventory().getItemInMainHand());
|
||||
disc.setData(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().addHiddenComponents(DataComponentTypes.JUKEBOX_PLAYABLE).build());
|
||||
ItemMeta meta = disc.getItemMeta();
|
||||
@Nullable List<Component> itemLore = new ArrayList<>();
|
||||
final TextComponent customLoreSong = Component.text().decoration(TextDecoration.ITALIC, false).content(song_name).color(NamedTextColor.GRAY).build();
|
||||
itemLore.add(customLoreSong);
|
||||
meta.lore(itemLore);
|
||||
if (resultIsMusicDisc) {
|
||||
if (!CustomDiscs.isMusicDiscEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_MUSIC_DISABLED.toString())); return 1; }
|
||||
ItemStack disc = new ItemStack(player.getInventory().getItemInMainHand());
|
||||
disc.setData(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().addHiddenComponents(DataComponentTypes.JUKEBOX_PLAYABLE).build());
|
||||
ItemMeta meta = disc.getItemMeta();
|
||||
@Nullable List<Component> itemLore = new ArrayList<>();
|
||||
final TextComponent customLoreSong = Component.text().decoration(TextDecoration.ITALIC, false).content(song_name).color(NamedTextColor.GRAY).build();
|
||||
itemLore.add(customLoreSong);
|
||||
meta.lore(itemLore);
|
||||
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
data.set(new NamespacedKey(this.plugin, "customdisc"), PersistentDataType.STRING, filename);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
} else if (resultIsHorn) {
|
||||
if (!CustomDiscs.isCustomHornEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_HORN_DISABLED.toString())); return 1; }
|
||||
final TextComponent customLoreSong = Component.text().decoration(TextDecoration.ITALIC, false).content(song_name).color(NamedTextColor.GRAY).build();
|
||||
MusicInstrument customInstrument = MusicInstrument.create(builder -> {
|
||||
builder.copyFrom(InstrumentKeys.ADMIRE_GOAT_HORN)
|
||||
.description(customLoreSong)
|
||||
.range(256.0f)
|
||||
.duration(1.0f)
|
||||
.soundEvent(TypedKey.create(
|
||||
RegistryKey.SOUND_EVENT,
|
||||
SoundEventKeys.INTENTIONALLY_EMPTY
|
||||
));
|
||||
});
|
||||
item.setData(DataComponentTypes.INSTRUMENT, customInstrument);
|
||||
|
||||
ItemStack disc = new ItemStack(player.getInventory().getItemInMainHand());
|
||||
disc.setData(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().addHiddenComponents(DataComponentTypes.JUKEBOX_PLAYABLE).build());
|
||||
ItemMeta meta = disc.getItemMeta();
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
data.set(new NamespacedKey(this.plugin, "customhorn"), PersistentDataType.STRING, filename);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
} else if (resultIsHead) {
|
||||
if (!CustomDiscs.isCustomHeadEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_HEAD_DISABLED.toString())); return 1; }
|
||||
final Component customLoreHead = Component.text().decoration(TextDecoration.ITALIC, false).content(song_name).color(NamedTextColor.GRAY).build();
|
||||
String serialized = GsonComponentSerializer.gson().serialize(customLoreHead);
|
||||
|
||||
ItemStack disc = new ItemStack(player.getInventory().getItemInMainHand());
|
||||
ItemMeta meta = disc.getItemMeta();
|
||||
@Nullable List<Component> itemLore = new ArrayList<>();
|
||||
final TextComponent customLoreSong = Component.text().decoration(TextDecoration.ITALIC, false).content(song_name).color(NamedTextColor.GRAY).build();
|
||||
itemLore.add(customLoreSong);
|
||||
meta.lore(itemLore);
|
||||
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
data.set(new NamespacedKey(this.plugin, "customhead"), PersistentDataType.STRING, filename);
|
||||
data.set(new NamespacedKey(this.plugin, "headlore"), PersistentDataType.STRING, serialized);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
data.set(new NamespacedKey(this.plugin, "customdisc"), PersistentDataType.STRING, filename);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CREATE_FILENAME.toString().replace("%filename%", filename)));
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CREATE_CUSTOM_NAME.toString().replace("%custom_name%", song_name)));
|
||||
return 1;
|
||||
@@ -124,8 +177,4 @@ public class CreateSubCommand extends CommandAPICommand {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isMusicDisc(ItemStack item) {
|
||||
return item.getType().toString().contains("MUSIC_DISC");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
package me.Navoei.customdiscsplugin.command.SubCommands;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.StringArgument;
|
||||
import dev.jorel.commandapi.arguments.TextArgument;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import org.codehaus.plexus.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -22,9 +26,12 @@ import java.net.URLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class DownloadSubCommand extends CommandAPICommand {
|
||||
private final CustomDiscs plugin;
|
||||
private final boolean debugModeResult = CustomDiscs.isDebugMode();
|
||||
|
||||
public DownloadSubCommand(CustomDiscs plugin) {
|
||||
super("download");
|
||||
@@ -32,34 +39,35 @@ public class DownloadSubCommand extends CommandAPICommand {
|
||||
|
||||
this.withFullDescription(NamedTextColor.GRAY + "Downloads a file from a given URL.");
|
||||
this.withUsage("/customdisc download <url> <filename.extension>");
|
||||
|
||||
this.withPermission("customdiscs.download");
|
||||
|
||||
this.withArguments(new TextArgument("url"));
|
||||
this.withArguments(new StringArgument("filename"));
|
||||
|
||||
this.executesPlayer(this::onCommandPlayer);
|
||||
this.executesConsole(this::onCommandConsole);
|
||||
}
|
||||
|
||||
|
||||
private int onCommandPlayer(Player player, CommandArguments arguments) {
|
||||
if (!player.hasPermission("customdiscs.download")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NO_PERMISSION.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
final Logger pluginLogger = plugin.getLogger();
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||
try {
|
||||
try {
|
||||
URI uri = new URI(Objects.requireNonNull(arguments.getByClass("url", String.class)));
|
||||
URL fileURL = uri.toURL();
|
||||
String filename = Objects.requireNonNull(arguments.getByClass("filename", String.class));
|
||||
|
||||
if(debugModeResult) {
|
||||
pluginLogger.info("DEBUG - Download File URL: " + fileURL);
|
||||
pluginLogger.info("DEBUG - File name: " + filename);
|
||||
}
|
||||
|
||||
if (filename.contains("../")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_FILENAME.toString()));
|
||||
return;
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
//System.out.println(filename);
|
||||
|
||||
String fileExtension = getFileExtension(filename);
|
||||
if (!fileExtension.equals("wav") && !fileExtension.equals("mp3") && !fileExtension.equals("flac")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_FORMAT.toString()));
|
||||
@@ -85,11 +93,17 @@ public class DownloadSubCommand extends CommandAPICommand {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CREATE_DISC.toString().replace("%filename%", filename)));
|
||||
} catch (URISyntaxException | MalformedURLException e) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.DOWNLOAD_ERROR.toString()));
|
||||
e.printStackTrace();
|
||||
pluginLogger.warning("A download error occurred.");
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.DOWNLOAD_ERROR.toString()));
|
||||
e.printStackTrace();
|
||||
pluginLogger.warning("A download error occurred.");
|
||||
if(debugModeResult) {
|
||||
pluginLogger.log(Level.SEVERE, "Exception output: ", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -109,4 +123,5 @@ public class DownloadSubCommand extends CommandAPICommand {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package me.Navoei.customdiscsplugin.command.SubCommands;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.TypeChecker;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.IntegerArgument;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class SetHornCooldownSubCommand extends CommandAPICommand {
|
||||
private final CustomDiscs plugin;
|
||||
|
||||
public SetHornCooldownSubCommand(CustomDiscs plugin) {
|
||||
super("goatcooldown");
|
||||
this.plugin = plugin;
|
||||
|
||||
this.withFullDescription(NamedTextColor.GRAY + "Set the cooldown for a modified goat horn (range from 1 to "+ this.plugin.hornMaxCooldown +" in ticks).");
|
||||
this.withUsage("/cd goatcooldown <range>");
|
||||
this.withPermission("customdiscs.horncooldown");
|
||||
|
||||
this.withArguments(new IntegerArgument("goatcooldown"));
|
||||
|
||||
this.executesPlayer(this::onCommandPlayer);
|
||||
this.executesConsole(this::onCommandConsole);
|
||||
}
|
||||
|
||||
private int onCommandPlayer(Player player, CommandArguments arguments) {
|
||||
if (!TypeChecker.isCustomGoatHornPlayer(player)) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NOT_HOLDING_MODIFIED_GOATHORN.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (TypeChecker.isCustomGoatHornPlayer(player)) {
|
||||
if (!CustomDiscs.isMusicDiscEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_HORN_DISABLED.toString())); return 1; }
|
||||
}
|
||||
|
||||
int goatcooldown = Objects.requireNonNull(arguments.getByClass("goatcooldown", Integer.class));
|
||||
|
||||
if (goatcooldown <= 0 || goatcooldown > this.plugin.hornMaxCooldown) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_COOLDOWN.toString().replace("%cooldown_value%", Integer.toString(this.plugin.hornMaxCooldown))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
ItemStack disc = new ItemStack(player.getInventory().getItemInMainHand());
|
||||
ItemMeta meta = disc.getItemMeta();
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
|
||||
data.set(new NamespacedKey(this.plugin, "customhorncoolodwn"), PersistentDataType.INTEGER, Math.min(goatcooldown, CustomDiscs.getInstance().hornMaxCooldown));
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CREATE_CUSTOM_GOAT_COOLDOWN.toString().replace("%custom_goat_cooldown%", Integer.toString(goatcooldown))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int onCommandConsole(ConsoleCommandSender executor, CommandArguments arguments) {
|
||||
executor.sendMessage(NamedTextColor.RED + "Only players can use this command : '"+arguments+"'!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
package me.Navoei.customdiscsplugin.command.SubCommands;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.TypeChecker;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.FloatArgument;
|
||||
import dev.jorel.commandapi.executors.CommandArguments;
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
//import org.bukkit.Bukkit;
|
||||
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
//import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
//import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class SetRangeSubCommand extends CommandAPICommand {
|
||||
private final CustomDiscs plugin;
|
||||
@@ -31,7 +30,8 @@ public class SetRangeSubCommand extends CommandAPICommand {
|
||||
|
||||
this.withFullDescription(NamedTextColor.GRAY + "Set the range of a disc to the defined value (range from 1 to "+ this.plugin.musicDiscMaxDistance +").");
|
||||
this.withUsage("/cd range <range>");
|
||||
|
||||
this.withPermission("customdiscs.range");
|
||||
|
||||
this.withArguments(new FloatArgument("range"));
|
||||
|
||||
this.executesPlayer(this::onCommandPlayer);
|
||||
@@ -41,28 +41,40 @@ public class SetRangeSubCommand extends CommandAPICommand {
|
||||
private int onCommandPlayer(Player player, CommandArguments arguments) {
|
||||
|
||||
ItemStack item = player.getInventory().getItemInMainHand();
|
||||
boolean resultIsCustomDisc = TypeChecker.isCustomMusicDisc(item);
|
||||
boolean resultIsCustomHorn = TypeChecker.isCustomGoatHornPlayer(player);
|
||||
boolean resultIsCustomHead = TypeChecker.isCustomHeadPlayer(player);
|
||||
|
||||
if (!isCustomDisc(item)) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NOT_HOLDING_DISC.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("customdiscs.range")) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NO_PERMISSION.toString()));
|
||||
if (!resultIsCustomDisc && !resultIsCustomHorn && !resultIsCustomHead) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.NOT_HOLDING_CORRECT_ITEM.toString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Float range = Objects.requireNonNull(arguments.getByClass("range", Float.class));
|
||||
|
||||
if ( range < 1 || range > this.plugin.musicDiscMaxDistance) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_RANGE.toString().replace("%range_value%", Float.toString(this.plugin.musicDiscMaxDistance))));
|
||||
Float configMusicDiscMaxDistance;
|
||||
if (resultIsCustomHorn) {
|
||||
if (!CustomDiscs.isCustomHornEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_HORN_DISABLED.toString())); return 1; }
|
||||
configMusicDiscMaxDistance = this.plugin.customHornMaxDistance;
|
||||
} else if (resultIsCustomHead) {
|
||||
if (!CustomDiscs.isCustomHeadEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_HEAD_DISABLED.toString())); return 1; }
|
||||
configMusicDiscMaxDistance = this.plugin.customHeadMaxDistance;
|
||||
} else {
|
||||
if (!CustomDiscs.isMusicDiscEnable()) { player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CUSTOM_MUSIC_DISABLED.toString())); return 1; }
|
||||
configMusicDiscMaxDistance = this.plugin.musicDiscMaxDistance;
|
||||
}
|
||||
|
||||
|
||||
if ( range < 1 || range > configMusicDiscMaxDistance) {
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.INVALID_RANGE.toString().replace("%range_value%", Float.toString(configMusicDiscMaxDistance))));
|
||||
return 1;
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
PersistentDataContainer data = meta.getPersistentDataContainer();
|
||||
data.set(new NamespacedKey(this.plugin, "range"), PersistentDataType.FLOAT, range);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
data.set(new NamespacedKey(this.plugin, "range"), PersistentDataType.FLOAT, range);
|
||||
player.getInventory().getItemInMainHand().setItemMeta(meta);
|
||||
|
||||
player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.PREFIX + Lang.CREATE_CUSTOM_RANGE.toString().replace("%custom_range%", Float.toString(range))));
|
||||
|
||||
return 1;
|
||||
@@ -73,9 +85,4 @@ public class SetRangeSubCommand extends CommandAPICommand {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean isCustomDisc(ItemStack item) {
|
||||
if (item==null) return false;
|
||||
return item.getType().toString().contains("MUSIC_DISC") && item.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(plugin, "customdisc"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
127
src/main/java/me/Navoei/customdiscsplugin/event/HeadPlay.java
Normal file
127
src/main/java/me/Navoei/customdiscsplugin/event/HeadPlay.java
Normal file
@@ -0,0 +1,127 @@
|
||||
package me.Navoei.customdiscsplugin.event;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.PlayerManager;
|
||||
import me.Navoei.customdiscsplugin.VoicePlugin;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.block.NotePlayEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
public class HeadPlay implements Listener{
|
||||
|
||||
CustomDiscs customDiscs = CustomDiscs.getInstance();
|
||||
PlayerManager playerManager = PlayerManager.instance();
|
||||
|
||||
// Triggered on every noteblock interaction.
|
||||
// Most of the function will only be executed if a custom player head is found on top of the noteblock.
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onNotePlay(NotePlayEvent event) throws IOException {
|
||||
Block noteBlock = event.getBlock();
|
||||
|
||||
if (noteBlock.getType() != Material.NOTE_BLOCK) return;
|
||||
|
||||
if (PlayerManager.instance().isAudioPlayerPlaying(noteBlock.getLocation())) return;
|
||||
|
||||
Block headBlock = noteBlock.getRelative(BlockFace.UP);
|
||||
if (headBlock.getType() != Material.PLAYER_HEAD) return;
|
||||
|
||||
Skull skull = (Skull) headBlock.getState();
|
||||
PersistentDataContainer persistentDataContainer = skull.getPersistentDataContainer();
|
||||
|
||||
if (persistentDataContainer.has(new NamespacedKey(customDiscs, "customhead"), PersistentDataType.STRING)) {
|
||||
|
||||
String soundFileName = persistentDataContainer.get(new NamespacedKey(customDiscs, "customhead"), PersistentDataType.STRING);
|
||||
|
||||
float range = CustomDiscs.getInstance().customHeadDistance;
|
||||
NamespacedKey customSoundRangeKey = new NamespacedKey(customDiscs, "range");
|
||||
NamespacedKey customLore = new NamespacedKey(customDiscs, "headlore");
|
||||
|
||||
if(persistentDataContainer.has(customSoundRangeKey, PersistentDataType.FLOAT)) {
|
||||
float soundRange = Optional.ofNullable(persistentDataContainer.get(customSoundRangeKey, PersistentDataType.FLOAT)).orElse(0f);
|
||||
range = Math.min(soundRange, CustomDiscs.getInstance().customHeadMaxDistance);
|
||||
}
|
||||
|
||||
Path soundFilePath = Path.of(customDiscs.getDataFolder().getPath(), "musicdata", soundFileName);
|
||||
|
||||
if (soundFilePath.toFile().exists()) {
|
||||
Component songNameComponent = Optional.ofNullable(persistentDataContainer.get(customLore, PersistentDataType.STRING)).map(GsonComponentSerializer.gson()::deserialize).orElse(Component.text("Unknown Song", NamedTextColor.GRAY));
|
||||
String songName = PlainTextComponentSerializer.plainText().serialize(songNameComponent);
|
||||
Component customActionBarSongPlaying = LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.NOW_PLAYING.toString().replace("%song_name%", songName));
|
||||
|
||||
assert VoicePlugin.voicechatServerApi != null;
|
||||
playerManager.playAudioHead(VoicePlugin.voicechatServerApi, soundFilePath, noteBlock, customActionBarSongPlaying, range);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
throw new FileNotFoundException("Sound file is missing!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Event to delay by 1 tick after a player head had been placed
|
||||
// Delay will only be triggered on custom player head created with this plugin
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onHeadPlace(BlockPlaceEvent event) {
|
||||
ItemStack item = event.getItemInHand();
|
||||
|
||||
if (item.getType() != Material.PLAYER_HEAD) return;
|
||||
if (!(item.getItemMeta() instanceof SkullMeta meta)) return;
|
||||
|
||||
PersistentDataContainer itemPDC = meta.getPersistentDataContainer();
|
||||
if (!itemPDC.has(new NamespacedKey(customDiscs, "customhead"), PersistentDataType.STRING)) return;
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(customDiscs, () -> {
|
||||
Block block = event.getBlockPlaced();
|
||||
if (block.getType() != Material.PLAYER_HEAD && block.getType() != Material.PLAYER_WALL_HEAD) return;
|
||||
|
||||
Skull skull = (Skull) block.getState();
|
||||
PersistentDataContainer blockPDC = skull.getPersistentDataContainer();
|
||||
|
||||
NamespacedKey headKey = new NamespacedKey(customDiscs, "customhead");
|
||||
NamespacedKey loreKey = new NamespacedKey(customDiscs, "headlore");
|
||||
NamespacedKey rangeKey = new NamespacedKey(customDiscs, "range");
|
||||
|
||||
if (itemPDC.has(headKey, PersistentDataType.STRING)) {
|
||||
String customheadValue = itemPDC.get(headKey, PersistentDataType.STRING);
|
||||
blockPDC.set(headKey, PersistentDataType.STRING, customheadValue);
|
||||
}
|
||||
|
||||
if (itemPDC.has(loreKey, PersistentDataType.STRING)) {
|
||||
String headloreValue = itemPDC.get(loreKey, PersistentDataType.STRING);
|
||||
blockPDC.set(loreKey, PersistentDataType.STRING, headloreValue);
|
||||
}
|
||||
|
||||
if (itemPDC.has(rangeKey, PersistentDataType.FLOAT)) {
|
||||
Float rangeValue = itemPDC.get(rangeKey, PersistentDataType.FLOAT);
|
||||
blockPDC.set(rangeKey, PersistentDataType.FLOAT, rangeValue);
|
||||
}
|
||||
|
||||
skull.update(true, true);
|
||||
}, 1L);
|
||||
}
|
||||
|
||||
}
|
||||
145
src/main/java/me/Navoei/customdiscsplugin/event/HornPlay.java
Normal file
145
src/main/java/me/Navoei/customdiscsplugin/event/HornPlay.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package me.Navoei.customdiscsplugin.event;
|
||||
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.PlayerManager;
|
||||
import me.Navoei.customdiscsplugin.TypeChecker;
|
||||
import me.Navoei.customdiscsplugin.VoicePlugin;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.MusicInstrument;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class HornPlay implements Listener{
|
||||
|
||||
CustomDiscs customDiscs = CustomDiscs.getInstance();
|
||||
PlayerManager playerManager = PlayerManager.instance();
|
||||
|
||||
private final List<Material> goatHornNotInteractable = Arrays.asList(
|
||||
Material.ANVIL,
|
||||
Material.ARMOR_STAND,
|
||||
Material.BARREL,
|
||||
Material.BEACON,
|
||||
Material.BLAST_FURNACE,
|
||||
Material.BREWING_STAND,
|
||||
Material.CARTOGRAPHY_TABLE,
|
||||
Material.CHIPPED_ANVIL,
|
||||
Material.CHISELED_BOOKSHELF,
|
||||
Material.COMMAND_BLOCK,
|
||||
Material.COMPARATOR,
|
||||
Material.CRAFTER,
|
||||
Material.CRAFTING_TABLE,
|
||||
Material.DAMAGED_ANVIL,
|
||||
Material.DAYLIGHT_DETECTOR,
|
||||
Material.DECORATED_POT,
|
||||
Material.DISPENSER,
|
||||
Material.DROPPER,
|
||||
Material.ENCHANTING_TABLE,
|
||||
Material.FLOWER_POT,
|
||||
Material.FURNACE,
|
||||
Material.GRINDSTONE,
|
||||
Material.HOPPER,
|
||||
Material.ITEM_FRAME,
|
||||
Material.LECTERN,
|
||||
Material.LEVER,
|
||||
Material.LOOM,
|
||||
Material.NOTE_BLOCK,
|
||||
Material.REPEATER,
|
||||
Material.SMITHING_TABLE,
|
||||
Material.SMOKER,
|
||||
Material.STONECUTTER,
|
||||
Material.STRUCTURE_BLOCK
|
||||
);
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerInteract(PlayerInteractEvent event) throws IOException {
|
||||
ItemStack item = event.getItem();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (item == null) return;
|
||||
if (item.getType() != Material.GOAT_HORN) return;
|
||||
|
||||
Block block = event.getClickedBlock();
|
||||
if (player.hasCooldown(Material.GOAT_HORN)) return;
|
||||
|
||||
if (TypeChecker.isCustomGoatHorn(event) && ((event.getAction() == Action.RIGHT_CLICK_BLOCK) || (event.getAction() == Action.RIGHT_CLICK_AIR))) {
|
||||
|
||||
if (!player.isSneaking() && block != null) {
|
||||
Material targetBlockType = block.getType();
|
||||
if (goatHornNotInteractable.contains(targetBlockType)) return;
|
||||
if (targetBlockType.name().contains("_BED") || targetBlockType.name().contains("_BOAT") || targetBlockType.name().contains("_BUTTON") || targetBlockType.name().contains("CHEST") || targetBlockType.name().contains("_DOOR") /*|| targetBlockType.name().contains("_FENCE_GATE") */|| targetBlockType.name().contains("_GATE") || targetBlockType.name().contains("MINECART") || targetBlockType.name().contains("POTTED_") || targetBlockType.name().contains("_SIGN") || targetBlockType.name().contains("_TRAPDOOR")) return;
|
||||
}
|
||||
|
||||
String soundFileName = event.getItem().getItemMeta().getPersistentDataContainer().get(new NamespacedKey(customDiscs, "customhorn"), PersistentDataType.STRING);
|
||||
|
||||
@Nonnull PersistentDataContainer persistentDataContainer = event.getItem().getItemMeta().getPersistentDataContainer();
|
||||
|
||||
float range = CustomDiscs.getInstance().customHornDistance;
|
||||
NamespacedKey customSoundRangeKey = new NamespacedKey(customDiscs, "range");
|
||||
|
||||
if(persistentDataContainer.has(customSoundRangeKey, PersistentDataType.FLOAT)) {
|
||||
float soundRange = Optional.ofNullable(persistentDataContainer.get(customSoundRangeKey, PersistentDataType.FLOAT)).orElse(0f);
|
||||
range = Math.min(soundRange, CustomDiscs.getInstance().customHornMaxDistance);
|
||||
}
|
||||
|
||||
int hornCooldown;
|
||||
NamespacedKey hornCooldownKey = new NamespacedKey(customDiscs, "customhorncoolodwn");
|
||||
if(persistentDataContainer.has(hornCooldownKey, PersistentDataType.INTEGER)) {
|
||||
hornCooldown = Math.min(persistentDataContainer.get(hornCooldownKey, PersistentDataType.INTEGER), CustomDiscs.getInstance().hornMaxCooldown);
|
||||
} else {
|
||||
hornCooldown = Math.min(CustomDiscs.getInstance().hornCooldown, CustomDiscs.getInstance().hornMaxCooldown);
|
||||
}
|
||||
|
||||
Path soundFilePath = Path.of(customDiscs.getDataFolder().getPath(), "musicdata", soundFileName);
|
||||
|
||||
if (soundFilePath.toFile().exists()) {
|
||||
|
||||
String songName = "Unknown sound";
|
||||
|
||||
MusicInstrument instrument = item.getDataOrDefault(DataComponentTypes.INSTRUMENT, null);
|
||||
if (instrument != null) {
|
||||
Component songNameComponent = instrument.description(); // This is the one you're asking for
|
||||
songName = PlainTextComponentSerializer.plainText().serialize(songNameComponent);
|
||||
} else {
|
||||
songName = "Unknown sound";
|
||||
}
|
||||
|
||||
Component customActionBarSongPlaying = LegacyComponentSerializer.legacyAmpersand().deserialize(Lang.NOW_PLAYING.toString().replace("%song_name%", songName));
|
||||
|
||||
assert VoicePlugin.voicechatServerApi != null;
|
||||
playerManager.playAudioHorn(VoicePlugin.voicechatServerApi, soundFilePath, player, customActionBarSongPlaying.asComponent(), range);
|
||||
player.setCooldown(Material.GOAT_HORN, hornCooldown);
|
||||
} else {
|
||||
player.sendMessage(NamedTextColor.RED + "Sound file not found.");
|
||||
event.setCancelled(true);
|
||||
throw new FileNotFoundException("Sound file is missing!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
package me.Navoei.customdiscsplugin.event;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.TooltipDisplay;
|
||||
import me.Navoei.customdiscsplugin.CustomDiscs;
|
||||
import me.Navoei.customdiscsplugin.PlayerManager;
|
||||
import me.Navoei.customdiscsplugin.VoicePlugin;
|
||||
import me.Navoei.customdiscsplugin.language.Lang;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.TooltipDisplay;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -24,7 +27,6 @@ import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.components.JukeboxPlayableComponent;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
@@ -112,7 +114,7 @@ public class JukeBox implements Listener{
|
||||
}
|
||||
|
||||
if (player.isSneaking() && !itemInvolvedInEvent.getType().equals(Material.AIR)) return;
|
||||
stopDisc(block);
|
||||
playerManager.stopDisc(block);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +127,7 @@ public class JukeBox implements Listener{
|
||||
Jukebox jukebox = (Jukebox) block.getState();
|
||||
if (!isCustomMusicDisc(jukebox.getRecord())) return;
|
||||
|
||||
stopDisc(block);
|
||||
playerManager.stopDisc(block);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
@@ -135,7 +137,7 @@ public class JukeBox implements Listener{
|
||||
if (explodedBlock.getType() == Material.JUKEBOX) {
|
||||
Jukebox jukebox = (Jukebox) explodedBlock.getState();
|
||||
if (!isCustomMusicDisc(jukebox.getRecord())) return;
|
||||
stopDisc(explodedBlock);
|
||||
playerManager.stopDisc(explodedBlock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +154,4 @@ public class JukeBox implements Listener{
|
||||
return itemStack.getItemMeta().getPersistentDataContainer().has(new NamespacedKey(customDiscs, "customdisc"));
|
||||
}
|
||||
|
||||
private void stopDisc(Block block) {
|
||||
playerManager.stopLocationalAudio(block.getLocation());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,12 +4,10 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public enum Lang {
|
||||
PREFIX("prefix", "&8[&6CustomDiscs&8]&r"),
|
||||
NO_PERMISSION("no-permission", "&rYou do not have permission to execute this command."),
|
||||
INVALID_FILENAME("invalid-filename", "&rThis is an invalid filename!"),
|
||||
INVALID_FORMAT("invalid-format", "&rFile must be in wav, flac, or mp3 format!"),
|
||||
FILE_NOT_FOUND("file-not-found", "&rFile not found!"),
|
||||
INVALID_ARGUMENTS("invalid-arguments", "&rInsufficient arguments. &7(&a%command_syntax%&7)"),
|
||||
NOT_HOLDING_DISC("not-holding-disc", "&rYou must hold a disc in your main hand."),
|
||||
NOT_HOLDING_CORRECT_ITEM("not-holding-correct-item", "&rYou must either hold a disc, goat horn or player head in your main hand."),
|
||||
CREATE_FILENAME("create-filename", "&7Your filename is: &a\"%filename%\"."),
|
||||
CREATE_CUSTOM_NAME("create-custom-name", "&7Your custom name is: &a\"%custom_name%\"."),
|
||||
DOWNLOADING_FILE("downloading-file", "&7Downloading file..."),
|
||||
@@ -18,9 +16,15 @@ public enum Lang {
|
||||
CREATE_DISC("create-disc", "&aCreate a disc by doing &7/cd create filename.extension \"Custom Lore\"&a."),
|
||||
DOWNLOAD_ERROR("download-error", "&rAn error has occurred while downloading."),
|
||||
NOW_PLAYING("now-playing","&6Now playing: %song_name%"),
|
||||
DISC_CONVERTED("disc-converted", "&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &7JukeboxPlayableComponent&f."),
|
||||
DISC_CONVERTED("disc-converted", "&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &ToolTipDisplay&f."),
|
||||
INVALID_RANGE("invalid-range","&rYou need to chose a range between 1 and %range_value%"),
|
||||
CREATE_CUSTOM_RANGE("create-custom-range", "&7Your range is set to: &a\"%custom_range%\".");
|
||||
CREATE_CUSTOM_RANGE("create-custom-range", "&7Your range is set to: &a\"%custom_range%\"."),
|
||||
NOT_HOLDING_MODIFIED_GOATHORN("not-holding-modified-goathorn", "&cYou must hold a modified goat horn in your main hand."),
|
||||
INVALID_COOLDOWN("invalid-cooldown","&cYou need to chose a cooldown between 1 and %cooldown_value% (in ticks)"),
|
||||
CREATE_CUSTOM_GOAT_COOLDOWN("create-custom-goat-cooldown", "&7Your goat horn cooldown is set to: &a\"%custom_goat_cooldown%\"."),
|
||||
CUSTOM_MUSIC_DISABLED("custom-music-disabled", "&7Custom music discs are disabled in the configuration."),
|
||||
CUSTOM_HEAD_DISABLED("custom-head-disabled", "&7Custom player heads are disabled in the configuration."),
|
||||
CUSTOM_HORN_DISABLED("custom-horn-disabled", "&7Custom goat horns are disabled in the configuration.");
|
||||
|
||||
private final String path;
|
||||
private final String def;
|
||||
@@ -67,6 +71,4 @@ public enum Lang {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
//Component textComponent = LegacyComponentSerializer.legacyAmpersand().deserialize(PlaceholderAPI.setPlaceholders(player, Lang.PREFIX + Lang.COMBAT.toString()));
|
||||
//player.sendMessage(textComponent);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,21 @@
|
||||
# [Music Disc Config]
|
||||
# [General CustomDiscs Config]
|
||||
|
||||
# The maximum download size in megabytes.
|
||||
max-download-size: 50
|
||||
|
||||
# The master volume of music discs from 0-1. (You can set values like 0.5 for 50% volume).
|
||||
music-disc-volume: 1
|
||||
|
||||
# Debug Mode - To display some more logging information and Stack Trace informations
|
||||
debugMode: false
|
||||
|
||||
# [Music Discs Config]
|
||||
|
||||
# Enable custom music discs.
|
||||
music-disc-enable: true
|
||||
|
||||
# Enable "Now playing" message for custom music discs.
|
||||
music-disc-playing-enable: true
|
||||
|
||||
# The distance from which music discs can be heard in blocks.
|
||||
music-disc-distance: 16
|
||||
@@ -6,15 +23,46 @@ music-disc-distance: 16
|
||||
# The max distance from which music discs can be heard in blocks.
|
||||
music-disc-max-distance: 256
|
||||
|
||||
# The master volume of music discs from 0-1. (You can set values like 0.5 for 50% volume).
|
||||
music-disc-volume: 1
|
||||
# [Goat Horns Config]
|
||||
|
||||
# The maximum download size in megabytes.
|
||||
max-download-size: 50
|
||||
# Enable custom goat horns.
|
||||
custom-horn-enable: true
|
||||
|
||||
#Custom Discs Help Page
|
||||
# Enable "Now playing" message for custom horns.
|
||||
custom-horn-playing-enable: true
|
||||
|
||||
# The distance from which custom horns can be heard in blocks.
|
||||
custom-horn-distance: 16
|
||||
|
||||
# The max distance from which custom horns can be heard in blocks.
|
||||
custom-horn-max-distance: 256
|
||||
|
||||
# The default cooldown time for horns in ticks from 1 to the max value of horn-max-cooldown (1 second is 20 ticks).
|
||||
horn-cooldown: 140
|
||||
|
||||
# The default max cooldown time for horns in ticks (1 second is 20 ticks).
|
||||
horn-max-cooldown: 6000
|
||||
|
||||
# [Player Heads Config]
|
||||
|
||||
# Enable custom player heads.
|
||||
custom-head-enable: true
|
||||
|
||||
# Enable "Now playing" message for player heads.
|
||||
custom-head-playing-enable: true
|
||||
|
||||
# The distance from which music discs can be heard in blocks.
|
||||
custom-head-distance: 16
|
||||
|
||||
# The max distance from which music discs can be heard in blocks.
|
||||
custom-head-max-distance: 256
|
||||
|
||||
|
||||
# [DO NOT EDIT BELOW THIS LINE - Help configuration]
|
||||
# Custom Discs Help Page
|
||||
help:
|
||||
- "&8-[&6CustomDiscs Help Page&8]-"
|
||||
- "&8-[&6CustomDiscs v5.0 - Help Page&8]-"
|
||||
- "&aAuthor&7: &6Navoei"
|
||||
- "&aContributors&7: &6alfw / &6Athar42"
|
||||
- "&fGit&0Hub&7: &9&ohttps://github.com/Navoei/CustomDiscs"
|
||||
- "&aContributors&7: &6Athar42 / &6alfw"
|
||||
- "&fGit&0Hub&7: &9&ohttps://github.com/Navoei/CustomDiscs"
|
||||
- "&aDiscord&7: &9&ohttps://discord.gg/YJpqruvZ97"
|
||||
BIN
src/main/resources/goat_horn_category.png
Normal file
BIN
src/main/resources/goat_horn_category.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 197 B |
@@ -1,19 +1,22 @@
|
||||
prefix: "&8[&6CustomDiscs&8]&r"
|
||||
no-permission: "&cYou do not have permission to execute this command."
|
||||
invalid-filename: "&cThis is an invalid filename!"
|
||||
no-disc-name-provided: "&cYou must provide a name for your disc."
|
||||
invalid-format: "&cFile must be in wav, flac, or mp3 format!"
|
||||
file-not-found: "&cFile not found!"
|
||||
invalid-arguments: "&cInvalid arguments. &7(&a%command_syntax%&7)"
|
||||
not-holding-disc: "&cYou must hold a disc in your main hand."
|
||||
create-filename: "&7Your filename is: &a\"%filename%\"."
|
||||
create-custom-name: "&7Your custom name is: &a\"%custom_name%\"."
|
||||
downloading-file: "&7Downloading file..."
|
||||
file-too-large: "&cThe file is larger than %max_download_size%MB."
|
||||
successful-download: "&aFile successfully downloaded to &7%file_path%&a."
|
||||
create-disc: "&aCreate a disc by doing &7/cd create %filename% \"Custom Lore\"&a."
|
||||
download-error: "&cAn error has occurred while downloading."
|
||||
now-playing: "&6Now playing: %song_name%"
|
||||
disc-converted: "&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &7ToolTipDisplay&f."
|
||||
invalid-range: "&cYou need to chose a range between 1 and %range_value%"
|
||||
create-custom-range: "&7Your range is set to: &a\"%custom_range%\"."
|
||||
prefix: '&8[&6CustomDiscs&8]&r'
|
||||
invalid-filename: '&cThis is an invalid filename!'
|
||||
invalid-format: '&cFile must be in wav, flac, or mp3 format!'
|
||||
file-not-found: '&cFile not found!'
|
||||
not-holding-correct-item: '&cYou must either hold a disc, goat horn or player head in your main hand.'
|
||||
create-filename: '&7Your filename is: &a"%filename%".'
|
||||
create-custom-name: '&7Your custom name is: &a"%custom_name%".'
|
||||
downloading-file: '&7Downloading file...'
|
||||
file-too-large: '&cThe file is larger than %max_download_size%MB.'
|
||||
successful-download: '&aFile successfully downloaded to &7%file_path%&a.'
|
||||
create-disc: '&aCreate a disc by doing &7/cd create %filename% "Custom Lore"&a.'
|
||||
download-error: '&cAn error has occurred while downloading.'
|
||||
now-playing: '&6Now playing: %song_name%'
|
||||
disc-converted: '&aConverted disc to new format! &fThis is due to changes in newer Minecraft versions which introduced &7ToolTipDisplay&f.'
|
||||
invalid-range: '&cYou need to chose a range between 1 and %range_value%'
|
||||
create-custom-range: '&7Your range is set to: &a"%custom_range%".'
|
||||
not-holding-modified-goathorn: '&cYou must hold a modified goat horn in your main hand.'
|
||||
invalid-cooldown: '&cYou need to chose a cooldown between 1 and %cooldown_value% (in ticks)'
|
||||
create-custom-goat-cooldown: '&7Your goat horn cooldown is set to: &a"%custom_goat_cooldown%".'
|
||||
custom-music-disabled: '&7Custom music discs are disabled in the configuration.'
|
||||
custom-head-disabled: '&7Custom player heads are disabled in the configuration.'
|
||||
custom-horn-disabled: '&7Custom goat horns are disabled in the configuration.'
|
||||
BIN
src/main/resources/player_head_category.png
Normal file
BIN
src/main/resources/player_head_category.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -4,7 +4,7 @@ main: me.Navoei.customdiscsplugin.CustomDiscs
|
||||
api-version: '${bukkit_api_version}'
|
||||
prefix: CustomDiscs
|
||||
authors: [ "Navoei", "Athar42", "alfw" ]
|
||||
description: A plugin which uses the Simple Voice Chat API to add custom music discs.
|
||||
description: A plugin which uses the Simple Voice Chat API to add custom music discs, goat horns and player's head.
|
||||
depend: [ "voicechat", "ProtocolLib" ]
|
||||
dependencies:
|
||||
server:
|
||||
|
||||
Reference in New Issue
Block a user