Writes a lot of code necessary for the scrapper

Adds the classes necessary for the new scrapper
Partly implements some scrapper functionality
Restructures some classes to reduce code duplication
Moves some classes to make some classes easier to find
Adds a bunch of TODOs where things have an unfinished implementation
This commit is contained in:
2023-11-14 16:04:48 +01:00
parent 1938a690c6
commit f3f3f66c38
40 changed files with 1788 additions and 594 deletions

View File

@ -0,0 +1,180 @@
package net.knarcraft.blacksmith.trait;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.knarcraft.blacksmith.config.TraitSettings;
import net.knarcraft.blacksmith.formatting.TimeFormatter;
import net.knarcraft.blacksmith.manager.EconomyManager;
import net.knarcraft.knarlib.formatting.StringFormatter;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
/**
* A custom trait that utilizes sessions
*/
public abstract class CustomTrait extends Trait {
protected Session session;
protected TraitSettings config;
protected final Map<UUID, Calendar> coolDowns = new HashMap<>();
protected long currentSessionStartTime = System.currentTimeMillis();
/**
* Instantiates a new custom trait
*
* @param name <p>The name of the new trait</p>
*/
protected CustomTrait(String name) {
super(name);
}
/**
* Sets the trait settings object containing this trait's configuration
*
* @param config <p>The trait settings to use</p>
*/
protected void setTraitSettings(TraitSettings config) {
this.config = config;
}
/**
* Starts a new session, and prepares to repair the player's item
*
* @param player <p>The player to start the session for</p>
*/
public abstract void startSession(@NotNull Player player);
/**
* Tries to continue the session for the given player
*
* @param player <p>The player to continue the session for</p>
*/
public void continueSession(@NotNull Player player) {
//Another player is using the blacksmith
if (session.isNotInSession(player)) {
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
return;
}
//The blacksmith is already reforging for the player
if (session.isRunning()) {
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
boolean showExactTime = showExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getBusyWorkingMessage(),
"{time}", TimeFormatter.formatTime(showExactTime, timeRemaining)));
return;
}
if (session.isSessionInvalid()) {
//Quit if the player cannot afford, or has changed their item
session = null;
} else {
//Start reforging for the player
startMainAction(npc, player);
}
}
/**
* Gets whether this blacksmith is already in a reforging session
*
* @return <p>Whether already in a salvage session</p>
*/
public boolean hasSession() {
return this.session != null;
}
/**
* Adds a cool-down for the given player's next blacksmith reforge
*
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
* @param waitUntil <p>The time when the player can interact again</p>
*/
public void addCoolDown(@NotNull UUID playerUUID, @NotNull Calendar waitUntil) {
coolDowns.put(playerUUID, waitUntil);
}
/**
* Unsets the session of this scrapper, making it ready for another round
*/
public void unsetSession() {
this.session = null;
}
/**
* Performs necessary work before the session is started or continued
*
* @param player <p>The player to prepare the session for</p>
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
*/
public boolean prepareForSession(@NotNull Player player) {
UUID playerId = player.getUniqueId();
//If cool-down has been disabled after it was set for this player, remove the cool-down
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
coolDowns.remove(playerId);
}
//Deny if permission is missing
if (!player.hasPermission("blacksmith.use")) {
return false;
}
//Deny if on cool-down, or remove cool-down if expired
if (coolDowns.get(playerId) != null) {
Calendar calendar = Calendar.getInstance();
if (!calendar.after(coolDowns.get(playerId))) {
int secondDifference = (int) (coolDowns.get(playerId).getTimeInMillis() - calendar.getTimeInMillis()) / 1000;
boolean exactTime = showExactTime();
sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(config.getCoolDownUnexpiredMessage(),
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
return false;
}
coolDowns.remove(playerId);
}
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
session = null;
}
return true;
}
/**
* Gets whether to show exact time when displaying the remaining time left
*
* @return <p>Whether to show exact time, or vague words</p>
*/
protected abstract boolean showExactTime();
/**
* Starts reforging the player's item
*
* @param npc <p>The NPC performing the reforge</p>
* @param player <p>The player that initiated the reforge</p>
*/
private void startMainAction(@NotNull NPC npc, @NotNull Player player) {
sendNPCMessage(this.npc, player, config.getStartWorkingMessage());
// TODO: Differentiate between blacksmiths and scrappers when withdrawing money
EconomyManager.withdraw(player);
session.scheduleAction();
ItemStack heldItem = player.getInventory().getItemInMainHand();
//Display the item in the NPC's hand
if (npc.getEntity() instanceof Player) {
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
} else {
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
}
//Remove the item from the player's inventory
player.getInventory().setItemInMainHand(null);
}
}