From f150eef319ada62ce999f00df68316fab17e0b09 Mon Sep 17 00:00:00 2001 From: Ted Pier Date: Sat, 18 Oct 2025 17:09:40 -0700 Subject: [PATCH] Initial Commit --- .gitignore | 113 ++++++++++++++++++ pom.xml | 68 +++++++++++ .../java/me/miningtcup/directXP/DirectXP.java | 110 +++++++++++++++++ src/main/resources/config.yml | 11 ++ src/main/resources/plugin.yml | 6 + 5 files changed, 308 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/me/miningtcup/directXP/DirectXP.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..fdafc81 --- /dev/null +++ b/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + me.miningtcup + directxp + 1.1 + jar + + directxp + + + 21 + UTF-8 + + + + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + + shade + + + + + + + + src/main/resources + true + + + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + + + + io.papermc.paper + paper-api + 1.21.8-R0.1-SNAPSHOT + provided + + + diff --git a/src/main/java/me/miningtcup/directXP/DirectXP.java b/src/main/java/me/miningtcup/directXP/DirectXP.java new file mode 100644 index 0000000..80665a5 --- /dev/null +++ b/src/main/java/me/miningtcup/directXP/DirectXP.java @@ -0,0 +1,110 @@ +package me.miningtcup.directXP; + +import org.bukkit.Sound; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.bukkit.Bukkit.getPluginManager; +import static org.bukkit.Bukkit.getScheduler; + +public final class DirectXP extends JavaPlugin implements Listener { + private final FileConfiguration config = getConfig(); + private final Map remainingDings = new HashMap<>(); + private final Map isPlaying = new HashMap<>(); + private final Map lastDingTime = new HashMap<>(); + + @Override + public void onEnable() { + saveDefaultConfig(); + this.getLogger().info("DirectXP is enabled."); + getPluginManager().registerEvents(this, this); + } + + @EventHandler + public void onEntityDeath(EntityDeathEvent event) { + reloadConfig(); + if (!config.getBoolean("entity-death", true)) return; + if (event.getDamageSource().getCausingEntity() instanceof Player player) { + int exp = event.getDroppedExp(); + player.giveExp(exp, true); + event.setDroppedExp(0); + ding(player, exp); + } + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + reloadConfig(); + if (!config.getBoolean("break-block", true)) return; + int exp = event.getExpToDrop(); + if (exp > 0) { + Player player = event.getPlayer(); + player.giveExp(exp, true); + event.setExpToDrop(0); + ding(player, exp); + } + } + + public void ding(Player player, int exp) { + reloadConfig(); + if (config.getBoolean("multi-sounds")) { + int newDings = calculateOrbs(exp).size(); + remainingDings.put(player, remainingDings.getOrDefault(player, 0) + newDings); + startPlaying(player); + } else { + reloadConfig(); + long currentTime = System.currentTimeMillis(); + int soundDelayMillis = config.getInt("sound-delay", 2) * 50; + long lastTime = lastDingTime.getOrDefault(player, 0L); + + if (currentTime - lastTime >= soundDelayMillis) { + lastDingTime.put(player, currentTime); + player.playSound(player.getLocation(), + Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.1F, (float) (0.55 + Math.random() * 0.7)); + } + } + } + + private void startPlaying(Player player) { + reloadConfig(); + if (isPlaying.getOrDefault(player, false)) return; + isPlaying.put(player, true); + + getScheduler().runTaskTimer(this, task -> { + int dingsLeft = remainingDings.getOrDefault(player, 0); + if (dingsLeft > 0) { + player.playSound(player.getLocation(), + Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.1F, (float) (0.55 + Math.random() * 0.7)); + remainingDings.put(player, dingsLeft - 1); + } else { + task.cancel(); + isPlaying.put(player, false); + } + }, 0, config.getInt("sound-delay", 2)); + } + + private static final int[] ORB_VALUES = {2477, 1237, 617, 307, 149, 73, 37, 17, 7, 3, 1}; + + public static List calculateOrbs(int totalExperience) { + List orbs = new ArrayList<>(); + + for (int value : ORB_VALUES) { + while (totalExperience >= value) { + totalExperience -= value; + orbs.add(value); + } + } + + return orbs; + } +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..d0b4fc4 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,11 @@ +# Should DirectXP apply to breaking blocks? +break-block: true + +# Should DirectXP apply to killing entities? +entity-death: true + +# Should multiple sounds be played if it's calculated the amount of exp dropped would have resulted in multiple orbs? +multi-sounds: true + +# How many ticks between sounds? 2 is vanilla. +sound-delay: 2 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..22964b2 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,6 @@ +name: DirectXP +version: '1.1' +main: me.miningtcup.directXP.DirectXP +api-version: '1.21' +authors: [ MiningTcup ] +description: Collect XP directly, instead of from orbs.