Improves code structure, and performs some necessary work for commands
This commit is contained in:
		
							
								
								
									
										248
									
								
								src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,248 @@
 | 
			
		||||
package net.knarcraft.blacksmith.trait;
 | 
			
		||||
 | 
			
		||||
import net.citizensnpcs.api.npc.NPC;
 | 
			
		||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
 | 
			
		||||
import net.knarcraft.blacksmith.config.NPCSettings;
 | 
			
		||||
import net.knarcraft.blacksmith.manager.EconomyManager;
 | 
			
		||||
import org.bukkit.NamespacedKey;
 | 
			
		||||
import org.bukkit.enchantments.Enchantment;
 | 
			
		||||
import org.bukkit.entity.LivingEntity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.bukkit.inventory.meta.Damageable;
 | 
			
		||||
import org.bukkit.inventory.meta.ItemMeta;
 | 
			
		||||
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A representation of the session between a player and a blacksmith
 | 
			
		||||
 */
 | 
			
		||||
public class ReforgeSession implements Runnable {
 | 
			
		||||
 | 
			
		||||
    private final BlacksmithTrait blacksmithTrait;
 | 
			
		||||
    private final Player player;
 | 
			
		||||
    private final NPC npc;
 | 
			
		||||
    private final ItemStack itemToReforge;
 | 
			
		||||
    private int taskId;
 | 
			
		||||
    private final NPCSettings config;
 | 
			
		||||
    private static final String[] enchantments = new String[Enchantment.values().length];
 | 
			
		||||
    private static final Random random = new Random();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new session
 | 
			
		||||
     *
 | 
			
		||||
     * @param blacksmithTrait <p>A reference to the blacksmith trait</p>
 | 
			
		||||
     * @param player          <p>The player initiating the session</p>
 | 
			
		||||
     * @param npc             <p>The Blacksmith NPC involved in the session</p>
 | 
			
		||||
     * @param config          <p>The config to use for the session</p>
 | 
			
		||||
     */
 | 
			
		||||
    ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, NPCSettings config) {
 | 
			
		||||
        this.blacksmithTrait = blacksmithTrait;
 | 
			
		||||
        this.player = player;
 | 
			
		||||
        this.npc = npc;
 | 
			
		||||
        itemToReforge = player.getInventory().getItemInMainHand();
 | 
			
		||||
        this.config = config;
 | 
			
		||||
 | 
			
		||||
        int i = 0;
 | 
			
		||||
        for (Enchantment enchantment : Enchantment.values()) {
 | 
			
		||||
            enchantments[i++] = enchantment.getKey().toString();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Runs the actual re-forge which fixes the item and gives it back to the player
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        player.sendMessage(reforgeItem() ? config.getSuccessMessage() : config.getFailMessage());
 | 
			
		||||
 | 
			
		||||
        //Stop the re-forged item from displaying in the blacksmith's hand
 | 
			
		||||
        if (npc.getEntity() instanceof Player) {
 | 
			
		||||
            ((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
 | 
			
		||||
        } else {
 | 
			
		||||
            Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Give the item back to the player
 | 
			
		||||
        if (!config.getDisableDelay()) {
 | 
			
		||||
            //If the player isn't online, drop the item to prevent it from disappearing
 | 
			
		||||
            if (config.getDropItem() || !player.isOnline()) {
 | 
			
		||||
                player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
 | 
			
		||||
            } else {
 | 
			
		||||
                player.getInventory().addItem(itemToReforge);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            player.getInventory().setItemInMainHand(itemToReforge);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Mark this blacksmith as available
 | 
			
		||||
        blacksmithTrait.unsetSession();
 | 
			
		||||
 | 
			
		||||
        // Start cool-down
 | 
			
		||||
        Calendar wait = Calendar.getInstance();
 | 
			
		||||
        wait.add(Calendar.SECOND, config.getReforgeCoolDown());
 | 
			
		||||
        blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs the actual re-forge where the item's damage is reduced
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>Whether the re-forge was successful. False if the blacksmith failed to fully repair the item.</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean reforgeItem() {
 | 
			
		||||
        if (random.nextInt(100) < config.getFailChance()) {
 | 
			
		||||
            failReforge();
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
            succeedReforge();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The method to run when a blacksmith successfully re-forges an item
 | 
			
		||||
     */
 | 
			
		||||
    private void succeedReforge() {
 | 
			
		||||
        // Remove any damage done to the item
 | 
			
		||||
        updateDamage(itemToReforge, 0);
 | 
			
		||||
 | 
			
		||||
        // Add random enchantments
 | 
			
		||||
        int roll = random.nextInt(100);
 | 
			
		||||
        if (!(roll < config.getExtraEnchantmentChance() &&
 | 
			
		||||
                itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments())) {
 | 
			
		||||
            // Abort if randomness isn't on our side, or if max enchantments has been reached
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // Choose a random enchantment
 | 
			
		||||
        Enchantment enchantment;
 | 
			
		||||
        int maxRetries = 100;
 | 
			
		||||
        int retries = 0;
 | 
			
		||||
        do {
 | 
			
		||||
            // Try to find a working enchantment for the re-forged item up to maxRetries times
 | 
			
		||||
            enchantment = Enchantment.getByKey(NamespacedKey.fromString(enchantments[random.nextInt(enchantments.length)]));
 | 
			
		||||
        } while ((enchantment == null || !enchantment.canEnchantItem(itemToReforge)) && (retries++ < maxRetries));
 | 
			
		||||
 | 
			
		||||
        if (enchantment != null && enchantment.canEnchantItem(itemToReforge)) {
 | 
			
		||||
            int randomBound = enchantment.getMaxLevel() - enchantment.getStartLevel();
 | 
			
		||||
            //A workaround for the random method's bound sometimes being negative
 | 
			
		||||
            if (randomBound >= 0) {
 | 
			
		||||
                itemToReforge.addEnchantment(enchantment, random.nextInt(randomBound) + enchantment.getStartLevel());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The method to run when a blacksmith fails re-forging an item
 | 
			
		||||
     */
 | 
			
		||||
    private void failReforge() {
 | 
			
		||||
        // Remove or downgrade existing enchantments
 | 
			
		||||
        for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) {
 | 
			
		||||
            if (random.nextBoolean()) {
 | 
			
		||||
                itemToReforge.removeEnchantment(enchantment);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (itemToReforge.getEnchantmentLevel(enchantment) > 1) {
 | 
			
		||||
                    itemToReforge.removeEnchantment(enchantment);
 | 
			
		||||
                    itemToReforge.addEnchantment(enchantment, 1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Damage the item
 | 
			
		||||
        short currentItemDurability = EconomyManager.getDurability(itemToReforge);
 | 
			
		||||
        short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
 | 
			
		||||
        short maxDurability = itemToReforge.getType().getMaxDurability();
 | 
			
		||||
        if (newDurability <= 0) {
 | 
			
		||||
            newDurability = (short) (maxDurability / 3);
 | 
			
		||||
        } else if (currentItemDurability + newDurability > maxDurability) {
 | 
			
		||||
            newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
 | 
			
		||||
        }
 | 
			
		||||
        updateDamage(itemToReforge, maxDurability - newDurability);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates the damage done to an item
 | 
			
		||||
     *
 | 
			
		||||
     * @param item      <p>The item to update damage for</p>
 | 
			
		||||
     * @param newDamage <p>The new damage done</p>
 | 
			
		||||
     */
 | 
			
		||||
    private void updateDamage(ItemStack item, int newDamage) {
 | 
			
		||||
        ItemMeta meta = item.getItemMeta();
 | 
			
		||||
        Damageable damageable = (Damageable) meta;
 | 
			
		||||
        if (damageable != null) {
 | 
			
		||||
            damageable.setDamage(newDamage);
 | 
			
		||||
        } else {
 | 
			
		||||
            BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to change damage of " + item);
 | 
			
		||||
        }
 | 
			
		||||
        item.setItemMeta(meta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether to end the current session
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If the player has switched their item, or the player cannot pay, this returns true.</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the current session should end</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean endSession() {
 | 
			
		||||
        // Prevent player from switching items during session
 | 
			
		||||
        ItemStack itemInHand = player.getInventory().getItemInMainHand();
 | 
			
		||||
        if (!itemToReforge.equals(itemInHand)) {
 | 
			
		||||
            player.sendMessage(config.getItemChangedMessage());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        // The player is unable to pay
 | 
			
		||||
        if (!EconomyManager.canPay(player)) {
 | 
			
		||||
            player.sendMessage(config.getInsufficientFundsMessage());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the current session is still running
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if the current session is still running</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isRunning() {
 | 
			
		||||
        return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the given player is currently in a re-forge session
 | 
			
		||||
     *
 | 
			
		||||
     * @param other <p>The player to check if is in session</p>
 | 
			
		||||
     * @return <p>True if the given player is in a re-forge session</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isInSession(Player other) {
 | 
			
		||||
        return player.getName().equals(other.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Begins the actual item reforging
 | 
			
		||||
     */
 | 
			
		||||
    public void beginReforge() {
 | 
			
		||||
        if (!config.getDisableCoolDown()) {
 | 
			
		||||
            //Finish the re-forge after a random delay between the max and min
 | 
			
		||||
            taskId = BlacksmithPlugin.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(
 | 
			
		||||
                    BlacksmithPlugin.getInstance(), this, (new Random().nextInt(config.getMaxReforgeDelay()) +
 | 
			
		||||
                            config.getMinReforgeDelay()) * 20L);
 | 
			
		||||
        } else {
 | 
			
		||||
            //Finish the re-forge as soon as possible
 | 
			
		||||
            taskId = BlacksmithPlugin.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(
 | 
			
		||||
                    BlacksmithPlugin.getInstance(), this, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the player currently in this reforge session
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The player currently in this reforge session</p>
 | 
			
		||||
     */
 | 
			
		||||
    public Player getPlayer() {
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user