7 Commits
1.0.0 ... dev

Author SHA1 Message Date
f4fa9e99a5 Makes sure NPC movements are the same
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-12-15 14:17:15 +01:00
b094d34c62 Adds debug output and a new working position
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-11-27 12:20:01 +01:00
9b04dd042e Adds debug output 2024-10-27 21:56:51 +01:00
f1f4526f9d Updates to the Blacksmith Snapshot API
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-09-27 01:43:13 +02:00
c013e3e65d Changes the Blacksmith version
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-08-07 16:24:27 +02:00
6ab99031dc Changes the FAQ somewhat
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-08-07 14:54:29 +02:00
c7365af9c4 Adds dependency information to the README
All checks were successful
KnarCraft/BlacksmithVisuals/pipeline/head This commit looks good
2024-08-07 14:08:03 +02:00
9 changed files with 118 additions and 33 deletions

View File

@ -4,6 +4,14 @@ This plugin adds additional visual and audial details to blacksmiths while they
they are working or not. It is recommended to put a mace or other hammer-like item in the NPC's off-hand for full they are working or not. It is recommended to put a mace or other hammer-like item in the NPC's off-hand for full
effect. effect.
## Dependencies
This plugin requires the following:
- [Blacksmith](https://www.spigotmc.org/resources/blacksmith.105938/)
- [Citizens](https://www.spigotmc.org/resources/citizens.13811/) (also a dependency for Blacksmith)
- [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/)
## Setting up a new NPC ## Setting up a new NPC
While most things are automatic, you should set the NPC's idle and working locations for the NPC to automatically move While most things are automatic, you should set the NPC's idle and working locations for the NPC to automatically move
@ -21,9 +29,9 @@ Remember to disable lookclose or adjust it as described in the FAQ.
### Citizens lookclose makes NPC rotate weirdly and not face its crafting station ### Citizens lookclose makes NPC rotate weirdly and not face its crafting station
It has been found that with some options, lookclose can still be used. An example of a working lookclose setup is: It has been found that with some options, lookclose can still be used. An example of a working lookclose setup is:
`/npc lookclose --linkedbody false --disablewhennavigating true --perplayer true --range 3 --targetnpcs false --headonly true --linkedbody false -r false` `/npc lookclose --linkedbody false --disablewhennavigating true --perplayer true --range 3 --targetnpcs false --headonly true --linkedbody false`
Some other options might work as well, but a lot of options won't, as it messes with manual NPC rotation. Keep that in The value of realistic looking `/npc lookclose -r` may also affect behavior. Some other options might work as well, but
mind. a lot of options won't, as it messes with manual NPC rotation. Keep that in mind.
### NPCs teleport part of the way while walking to or from a crafting station ### NPCs teleport part of the way while walking to or from a crafting station

View File

@ -6,7 +6,7 @@
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>BlacksmithVisuals</artifactId> <artifactId>BlacksmithVisuals</artifactId>
<version>1.0.0</version> <version>1.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>BlacksmithVisuals</name> <name>BlacksmithVisuals</name>
@ -111,7 +111,7 @@
<dependency> <dependency>
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>blacksmith</artifactId> <artifactId>blacksmith</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.1.3-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -24,6 +24,7 @@ public final class BlacksmithVisuals extends JavaPlugin {
private static BlacksmithVisuals instance; private static BlacksmithVisuals instance;
private ConfigurationManager configurationManager; private ConfigurationManager configurationManager;
private NPCDataManager npcDataManager; private NPCDataManager npcDataManager;
private boolean debug = false;
@Override @Override
public void onEnable() { public void onEnable() {
@ -35,6 +36,8 @@ public final class BlacksmithVisuals extends JavaPlugin {
this.reloadConfig(); this.reloadConfig();
this.saveConfig(); this.saveConfig();
this.debug = this.getConfig().getBoolean("debug", false);
try { try {
this.configurationManager = new ConfigurationManager(this.getConfig()); this.configurationManager = new ConfigurationManager(this.getConfig());
} catch (InvalidConfigurationException exception) { } catch (InvalidConfigurationException exception) {
@ -62,6 +65,20 @@ public final class BlacksmithVisuals extends JavaPlugin {
// Plugin shutdown logic // Plugin shutdown logic
} }
/**
* Logs a debug message
*
* @param message <p>The debug message to log</p>
*/
public static void debug(@NotNull String message) {
BlacksmithVisuals instance = getInstance();
if (instance.debug) {
instance.getLogger().log(Level.INFO, "[Debug] " + message);
} else {
instance.getLogger().log(Level.FINE, message);
}
}
/** /**
* Reloads the configuration file * Reloads the configuration file
*/ */

View File

@ -11,6 +11,7 @@ import org.bukkit.SoundCategory;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -34,7 +35,8 @@ public class PlayTestSoundCommand implements TabExecutor {
return true; return true;
} }
if (arguments.length < 2) { Entity entity = npc.getEntity();
if (arguments.length < 2 || !npc.isSpawned() || entity == null) {
return false; return false;
} }
@ -62,8 +64,7 @@ public class PlayTestSoundCommand implements TabExecutor {
return false; return false;
} }
SoundData soundData = new SoundData(soundCategory, sound, volume, pitch, 0, true); SoundHelper.playSound(entity, new SoundData(soundCategory, sound, volume, pitch, 0, true));
SoundHelper.playSound(npc.getEntity(), soundData);
return true; return true;
} }

View File

@ -65,37 +65,44 @@ public class BlacksmithListener implements Listener {
@EventHandler @EventHandler
public void onDefaultSound(@NotNull NPCSoundEvent event) { public void onDefaultSound(@NotNull NPCSoundEvent event) {
BlacksmithVisuals.debug("Detected onDefaultSound event");
event.setCancelled(true); event.setCancelled(true);
} }
@EventHandler @EventHandler
public void onReforgeStart(@NotNull BlacksmithReforgeStartEvent event) { public void onReforgeStart(@NotNull BlacksmithReforgeStartEvent event) {
BlacksmithVisuals.debug("Detected onReforgeStart event");
runWorkingAnimation(event, SoundIdentifier.REFORGING_WORKING, this.configurationManager.getBlacksmithAnimationData()); runWorkingAnimation(event, SoundIdentifier.REFORGING_WORKING, this.configurationManager.getBlacksmithAnimationData());
} }
@EventHandler @EventHandler
public void onSalvageStart(@NotNull ScrapperSalvageStartEvent event) { public void onSalvageStart(@NotNull ScrapperSalvageStartEvent event) {
BlacksmithVisuals.debug("Detected onSalvageStart event");
runWorkingAnimation(event, SoundIdentifier.SALVAGING_WORKING, this.configurationManager.getScrapperAnimationData()); runWorkingAnimation(event, SoundIdentifier.SALVAGING_WORKING, this.configurationManager.getScrapperAnimationData());
} }
@EventHandler @EventHandler
public void onReforgeSuccess(@NotNull BlacksmithReforgeSucceedEvent event) { public void onReforgeSuccess(@NotNull BlacksmithReforgeSucceedEvent event) {
SoundHelper.playSound(event.getNpc().getEntity(), this.configurationManager.getSoundData(SoundIdentifier.REFORGING_SUCCESS)); BlacksmithVisuals.debug("Detected onReforgeSuccess event");
SoundHelper.playSound(event.getEntity(), this.configurationManager.getSoundData(SoundIdentifier.REFORGING_SUCCESS));
} }
@EventHandler @EventHandler
public void onSalvageSuccess(@NotNull ScrapperSalvageSucceedEvent event) { public void onSalvageSuccess(@NotNull ScrapperSalvageSucceedEvent event) {
SoundHelper.playSound(event.getNpc().getEntity(), this.configurationManager.getSoundData(SoundIdentifier.SALVAGING_SUCCESS)); BlacksmithVisuals.debug("Detected onSalvageSuccess event");
SoundHelper.playSound(event.getEntity(), this.configurationManager.getSoundData(SoundIdentifier.SALVAGING_SUCCESS));
} }
@EventHandler @EventHandler
public void onReforgeFail(@NotNull BlacksmithReforgeFailEvent event) { public void onReforgeFail(@NotNull BlacksmithReforgeFailEvent event) {
SoundHelper.playSound(event.getNpc().getEntity(), this.configurationManager.getSoundData(SoundIdentifier.REFORGING_FAILURE)); BlacksmithVisuals.debug("Detected onReforgeFail event");
SoundHelper.playSound(event.getEntity(), this.configurationManager.getSoundData(SoundIdentifier.REFORGING_FAILURE));
} }
@EventHandler @EventHandler
public void onSalvageFail(@NotNull ScrapperSalvageFailEvent event) { public void onSalvageFail(@NotNull ScrapperSalvageFailEvent event) {
SoundHelper.playSound(event.getNpc().getEntity(), this.configurationManager.getSoundData(SoundIdentifier.SALVAGING_FAILURE)); BlacksmithVisuals.debug("Detected onSalvageFail event");
SoundHelper.playSound(event.getEntity(), this.configurationManager.getSoundData(SoundIdentifier.SALVAGING_FAILURE));
} }
/** /**
@ -107,36 +114,45 @@ public class BlacksmithListener implements Listener {
*/ */
private void runWorkingAnimation(@NotNull ActionStartEvent event, @NotNull SoundIdentifier soundIdentifier, private void runWorkingAnimation(@NotNull ActionStartEvent event, @NotNull SoundIdentifier soundIdentifier,
@NotNull AnimationData animationData) { @NotNull AnimationData animationData) {
BlacksmithVisuals.debug("Preparing to run working animation");
BlacksmithVisuals instance = BlacksmithVisuals.getInstance(); BlacksmithVisuals instance = BlacksmithVisuals.getInstance();
BukkitScheduler scheduler = Bukkit.getScheduler(); BukkitScheduler scheduler = Bukkit.getScheduler();
NPC npc = event.getNpc(); NPC npc = event.getNpc();
NPCPosition npcPosition = NPCPosition.getFromMaterial(event.getCraftingStation()); NPCPosition npcPosition = NPCPosition.getFromMaterial(event.getCraftingStation());
long delay = moveToWorkingPosition(npc, npcPosition); BlacksmithVisuals.debug("Found NPC position: " + npcPosition);
long delay = moveToWorkingPosition(npc, event.getEntity(), npcPosition);
BlacksmithVisuals.debug("Calculated delay to: " + delay);
if (npc.hasTrait(LookClose.class)) { if (npc.hasTrait(LookClose.class)) {
BlacksmithVisuals.debug("Found LookClose trait");
LookClose trait = npc.getTraitNullable(LookClose.class); LookClose trait = npc.getTraitNullable(LookClose.class);
this.oldLookRanges.put(npc.getUniqueId(), trait.getRange()); this.oldLookRanges.put(npc.getUniqueId(), trait.getRange());
trait.setRange(0); trait.setRange(0);
BlacksmithVisuals.debug("Edited LookClose range");
} }
long finishTime = event.getActionDurationTicks() - (2 * delay); long finishTime = event.getActionDurationTicks() - (2 * delay);
scheduler.scheduleSyncDelayedTask(instance, () -> startWorkAnimation(npc.getEntity(), BlacksmithVisuals.debug("Scheduling work animation and back movement");
scheduler.scheduleSyncDelayedTask(instance, () -> startWorkAnimation(event.getEntity(),
this.configurationManager.getSoundData(soundIdentifier), animationData, finishTime - 20, npcPosition), delay); this.configurationManager.getSoundData(soundIdentifier), animationData, finishTime - 20, npcPosition), delay);
scheduler.scheduleSyncDelayedTask(instance, () -> moveBack(event.getNpc()), finishTime); scheduler.scheduleSyncDelayedTask(instance, () -> moveBack(event.getNpc(), event.getEntity()), finishTime);
} }
/** /**
* Moves an NPC back to its idle position * Moves an NPC back to its idle position
* *
* @param npc <p>The NPC to move</p> * @param npc <p>The NPC to move</p>
* @param entity <p>The entity of the NPC</p>
*/ */
private void moveBack(@NotNull NPC npc) { private void moveBack(@NotNull NPC npc, @NotNull Entity entity) {
if (!npc.isSpawned()) { if (!npc.isSpawned()) {
BlacksmithVisuals.debug("NPC isn't spawned, and thus cannot be moved back");
return; return;
} }
NPCData npcData = BlacksmithVisuals.getInstance().getNpcDataManager().getData(npc.getUniqueId()); NPCData npcData = BlacksmithVisuals.getInstance().getNpcDataManager().getData(npc.getUniqueId());
if (npcData == null) { if (npcData == null) {
BlacksmithVisuals.debug("Unable to get NPC data for NPC");
return; return;
} }
@ -153,27 +169,29 @@ public class BlacksmithListener implements Listener {
if (oldRange != null) { if (oldRange != null) {
trait.setRange(oldRange); trait.setRange(oldRange);
} }
BlacksmithVisuals.debug("Restored LookCLose range");
} }
Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () -> moveNPC(npc, entity, targetLocation);
npc.getEntity().teleport(targetLocation), getWalkTime(npc.getEntity().getLocation(), targetLocation));
npc.getNavigator().setTarget(targetLocation);
} }
/** /**
* Moves a npc to its working position * Moves a npc to its working position
* *
* @param npc <p>The NPC to move</p> * @param npc <p>The NPC to move</p>
* @param entity <p>The entity of the NPC</p>
* @param npcPosition <p>The npc position to move to</p> * @param npcPosition <p>The npc position to move to</p>
* @return <p>The time the move will take</p> * @return <p>The time the move will take</p>
*/ */
private long moveToWorkingPosition(@NotNull NPC npc, @Nullable NPCPosition npcPosition) { private long moveToWorkingPosition(@NotNull NPC npc, @NotNull Entity entity, @Nullable NPCPosition npcPosition) {
if (!npc.isSpawned() || npcPosition == null) { if (!npc.isSpawned() || npcPosition == null) {
BlacksmithVisuals.debug("The NPC isn't spawned, or its working position doesn't exist");
return 0; return 0;
} }
NPCData npcData = BlacksmithVisuals.getInstance().getNpcDataManager().getData(npc.getUniqueId()); NPCData npcData = BlacksmithVisuals.getInstance().getNpcDataManager().getData(npc.getUniqueId());
if (npcData == null) { if (npcData == null) {
BlacksmithVisuals.debug("NPC sata could not be retrieved");
return 0; return 0;
} }
@ -182,6 +200,7 @@ public class BlacksmithListener implements Listener {
targetLocation = npcData.positions().get(NPCPosition.WORKING_REPAIRABLE); targetLocation = npcData.positions().get(NPCPosition.WORKING_REPAIRABLE);
} }
if (targetLocation == null) { if (targetLocation == null) {
BlacksmithVisuals.debug("Working location not set for WORKING_REPAIRABLE");
return 0; return 0;
} }
@ -190,18 +209,30 @@ public class BlacksmithListener implements Listener {
npc.getName() + " is unreachable!"); npc.getName() + " is unreachable!");
return 0; return 0;
} }
Location finalTargetLocation = targetLocation;
return moveNPC(npc, entity, targetLocation);
}
/**
* Moves an NPC to a different location
*
* @param npc <p>The NPC to be moved</p>
* @param entity <p>The NPC's entity</p>
* @param finalTargetLocation <p>The location the NPC should be moved to</p>
* @return <p>The assumed time it will take the NPC to get to the position</p>
*/
private long moveNPC(@NotNull NPC npc, @NotNull Entity entity, @NotNull Location finalTargetLocation) {
// Move NPC using Citizens path-finding // Move NPC using Citizens path-finding
Location current = npc.getEntity().getLocation().clone(); BlacksmithVisuals.debug("Preparing rotation and walk to working location");
npc.teleport(current.setDirection(targetLocation.toVector().subtract(current.toVector())), PlayerTeleportEvent.TeleportCause.PLUGIN); Location current = entity.getLocation().clone();
npc.teleport(current.setDirection(finalTargetLocation.toVector().subtract(current.toVector())), PlayerTeleportEvent.TeleportCause.PLUGIN);
Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () -> npc.getNavigator().setTarget(finalTargetLocation), 2); Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () -> npc.getNavigator().setTarget(finalTargetLocation), 2);
// Teleport the NPC tp get it in the exact final location // Teleport the NPC tp get it in the exact final location
long walkTime = getWalkTime(npc.getEntity().getLocation(), targetLocation); long walkTime = getWalkTime(entity.getLocation(), finalTargetLocation);
BlacksmithVisuals.debug("Queuing teleportation to working position");
Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () -> Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () ->
npc.getEntity().teleport(finalTargetLocation), walkTime); entity.teleport(finalTargetLocation, PlayerTeleportEvent.TeleportCause.PLUGIN), walkTime);
return walkTime; return walkTime;
} }
@ -217,12 +248,15 @@ public class BlacksmithListener implements Listener {
private void startWorkAnimation(@NotNull Entity entity, @NotNull SoundData soundData, private void startWorkAnimation(@NotNull Entity entity, @NotNull SoundData soundData,
@NotNull AnimationData animationData, long durationTicks, @NotNull AnimationData animationData, long durationTicks,
@Nullable NPCPosition npcPosition) { @Nullable NPCPosition npcPosition) {
BlacksmithVisuals.debug("Starting work animation");
BlacksmithVisuals instance = BlacksmithVisuals.getInstance(); BlacksmithVisuals instance = BlacksmithVisuals.getInstance();
BukkitScheduler scheduler = Bukkit.getScheduler(); BukkitScheduler scheduler = Bukkit.getScheduler();
BlacksmithVisuals.debug("Scheduling animation");
int playWorkSound = scheduler.scheduleSyncRepeatingTask(instance, int playWorkSound = scheduler.scheduleSyncRepeatingTask(instance,
() -> animateNPC(entity, soundData, animationData, npcPosition), 20, animationData.animationDelay()); () -> animateNPC(entity, soundData, animationData, npcPosition), 20, animationData.animationDelay());
scheduler.scheduleSyncDelayedTask(instance, () -> scheduler.cancelTask(playWorkSound), durationTicks); scheduler.scheduleSyncDelayedTask(instance, () -> scheduler.cancelTask(playWorkSound), durationTicks);
BlacksmithVisuals.debug("Stopped working animation");
} }
/** /**
@ -248,21 +282,26 @@ public class BlacksmithListener implements Listener {
*/ */
private void animateNPC(@NotNull Entity entity, @NotNull SoundData soundData, @NotNull AnimationData animationData, private void animateNPC(@NotNull Entity entity, @NotNull SoundData soundData, @NotNull AnimationData animationData,
@Nullable NPCPosition npcPosition) { @Nullable NPCPosition npcPosition) {
if (random.nextInt(100) >= animationData.animationChance()) {
return;
}
SoundHelper.playSound(entity, soundData);
// Don't play disabled animations // Don't play disabled animations
if (!animationData.animateOffHand()) { if (!animationData.animateOffHand()) {
BlacksmithVisuals.debug("Offhand animation is disabled");
return; return;
} }
if (random.nextInt(100) >= animationData.animationChance()) {
BlacksmithVisuals.debug("Animation skipped because of RNG");
return;
}
BlacksmithVisuals.debug("Playing work sound");
SoundHelper.playSound(entity, soundData);
if (soundData.offsetTicks() < 0) { if (soundData.offsetTicks() < 0) {
BlacksmithVisuals.debug("Delaying off-hand animation");
Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(),
() -> animateOffhand(entity), -soundData.offsetTicks()); () -> animateOffhand(entity), -soundData.offsetTicks());
} else { } else {
BlacksmithVisuals.debug("Animating off-hand");
animateOffhand(entity); animateOffhand(entity);
} }
@ -270,6 +309,7 @@ public class BlacksmithListener implements Listener {
npcPosition = NPCPosition.WORKING_REPAIRABLE; npcPosition = NPCPosition.WORKING_REPAIRABLE;
} }
for (int i = 0; i < random.nextInt(5) + 1; i++) { for (int i = 0; i < random.nextInt(5) + 1; i++) {
BlacksmithVisuals.debug("Spawning particle");
spawnSparkParticle(entity, npcPosition); spawnSparkParticle(entity, npcPosition);
} }
} }
@ -281,6 +321,7 @@ public class BlacksmithListener implements Listener {
* @param npcPosition <p>The npc potion to spawn a particle for</p> * @param npcPosition <p>The npc potion to spawn a particle for</p>
*/ */
private void spawnSparkParticle(@NotNull Entity entity, @NotNull NPCPosition npcPosition) { private void spawnSparkParticle(@NotNull Entity entity, @NotNull NPCPosition npcPosition) {
BlacksmithVisuals.debug("Preparing particle spawning");
double randomX = this.random.nextDouble(-1, 1); double randomX = this.random.nextDouble(-1, 1);
double randomY = this.random.nextDouble(0.1, 1); double randomY = this.random.nextDouble(0.1, 1);
double randomZ = this.random.nextDouble(-1, 1); double randomZ = this.random.nextDouble(-1, 1);
@ -291,8 +332,10 @@ public class BlacksmithListener implements Listener {
particle = Particle.FLAME; particle = Particle.FLAME;
} }
Location spawnLocation = entity.getLocation().clone().getBlock().getRelative(entity.getFacing()).getLocation().add(0.5, 0, 0.5); Location spawnLocation = entity.getLocation().clone().getBlock().getRelative(entity.getFacing()).getLocation().add(0.5, 0, 0.5);
BlacksmithVisuals.debug("Calculated particle location to " + spawnLocation);
ParticleConfig particleConfig = new ParticleConfig(ParticleMode.SINGLE, particle, 0, 0, 1.1, randomX, randomY, randomZ, 0.1); ParticleConfig particleConfig = new ParticleConfig(ParticleMode.SINGLE, particle, 0, 0, 1.1, randomX, randomY, randomZ, 0.1);
ParticleHelper.spawnParticle(entity.getWorld(), spawnLocation, particleConfig, 1); ParticleHelper.spawnParticle(entity.getWorld(), spawnLocation, particleConfig, 1);
BlacksmithVisuals.debug("Spawned particle");
} }
/** /**
@ -301,6 +344,7 @@ public class BlacksmithListener implements Listener {
* @param entity <p>The entity to animate</p> * @param entity <p>The entity to animate</p>
*/ */
private void animateOffhand(@NotNull Entity entity) { private void animateOffhand(@NotNull Entity entity) {
BlacksmithVisuals.debug("Preparing off-hand animation");
ProtocolManager manager = ProtocolLibrary.getProtocolManager(); ProtocolManager manager = ProtocolLibrary.getProtocolManager();
PacketContainer packet = manager.createPacket(PacketType.Play.Server.ANIMATION); PacketContainer packet = manager.createPacket(PacketType.Play.Server.ANIMATION);
packet.getIntegers().write(0, entity.getEntityId()); packet.getIntegers().write(0, entity.getEntityId());
@ -308,9 +352,11 @@ public class BlacksmithListener implements Listener {
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getWorld().equals(entity.getWorld())) { if (player.getWorld().equals(entity.getWorld())) {
BlacksmithVisuals.debug("Sending animation packet to " + player);
manager.sendServerPacket(player, packet); manager.sendServerPacket(player, packet);
} }
} }
BlacksmithVisuals.debug("Finished sending animation packets");
} }

View File

@ -77,6 +77,7 @@ public class NPCDataManager {
npcSection.set("workingPositionNetherite", entry.getValue().positions().get(NPCPosition.WORKING_NETHERITE)); npcSection.set("workingPositionNetherite", entry.getValue().positions().get(NPCPosition.WORKING_NETHERITE));
npcSection.set("workingPositionCrafting", entry.getValue().positions().get(NPCPosition.WORKING_CRAFTING)); npcSection.set("workingPositionCrafting", entry.getValue().positions().get(NPCPosition.WORKING_CRAFTING));
npcSection.set("workingPositionRepairable", entry.getValue().positions().get(NPCPosition.WORKING_REPAIRABLE)); npcSection.set("workingPositionRepairable", entry.getValue().positions().get(NPCPosition.WORKING_REPAIRABLE));
npcSection.set("workingPositionEnchantedBook", entry.getValue().positions().get(NPCPosition.WORKING_SPLITTING));
npcSection.set("idlePosition", entry.getValue().positions().get(NPCPosition.IDLE)); npcSection.set("idlePosition", entry.getValue().positions().get(NPCPosition.IDLE));
} }
configuration.save(configurationFile); configuration.save(configurationFile);
@ -106,6 +107,7 @@ public class NPCDataManager {
locationMap.put(NPCPosition.WORKING_NETHERITE, section.getLocation("workingPositionNetherite")); locationMap.put(NPCPosition.WORKING_NETHERITE, section.getLocation("workingPositionNetherite"));
locationMap.put(NPCPosition.WORKING_CRAFTING, section.getLocation("workingPositionCrafting")); locationMap.put(NPCPosition.WORKING_CRAFTING, section.getLocation("workingPositionCrafting"));
locationMap.put(NPCPosition.WORKING_REPAIRABLE, section.getLocation("workingPositionRepairable")); locationMap.put(NPCPosition.WORKING_REPAIRABLE, section.getLocation("workingPositionRepairable"));
locationMap.put(NPCPosition.WORKING_SPLITTING, section.getLocation("workingPositionEnchantedBook"));
locationMap.put(NPCPosition.IDLE, section.getLocation("idlePosition")); locationMap.put(NPCPosition.IDLE, section.getLocation("idlePosition"));
npcDataMap.put(UUID.fromString(configurationSectionKey), new NPCData(locationMap)); npcDataMap.put(UUID.fromString(configurationSectionKey), new NPCData(locationMap));
} }

View File

@ -33,6 +33,11 @@ public enum NPCPosition {
* The position the NPC should be in while un-crafting items * The position the NPC should be in while un-crafting items
*/ */
WORKING_CRAFTING("crafting-workstation", List.of(ScrapperTrait.class)), WORKING_CRAFTING("crafting-workstation", List.of(ScrapperTrait.class)),
/**
* The position the NPC should be in while salvaging an enchanted book
*/
WORKING_SPLITTING("enchanted-book-workstation", List.of(ScrapperTrait.class)),
; ;
private final String positionName; private final String positionName;
@ -71,6 +76,7 @@ public enum NPCPosition {
case CRAFTING_TABLE -> NPCPosition.WORKING_CRAFTING; case CRAFTING_TABLE -> NPCPosition.WORKING_CRAFTING;
case ANVIL -> NPCPosition.WORKING_REPAIRABLE; case ANVIL -> NPCPosition.WORKING_REPAIRABLE;
case SMITHING_TABLE -> NPCPosition.WORKING_NETHERITE; case SMITHING_TABLE -> NPCPosition.WORKING_NETHERITE;
case ENCHANTING_TABLE -> NPCPosition.WORKING_SPLITTING;
default -> null; default -> null;
}; };
} }

View File

@ -25,15 +25,18 @@ public final class SoundHelper {
public static void playSound(@NotNull Entity entity, @NotNull SoundData soundData) { public static void playSound(@NotNull Entity entity, @NotNull SoundData soundData) {
// Don't play disabled sounds // Don't play disabled sounds
if (!soundData.enabled()) { if (!soundData.enabled()) {
BlacksmithVisuals.debug("Skipping sound " + soundData.sound() + " as it's disabled");
return; return;
} }
World world = entity.getLocation().getWorld(); World world = entity.getLocation().getWorld();
if (world == null) { if (world == null) {
BlacksmithVisuals.debug("Could not play sound, as world is null");
return; return;
} }
int delay = Math.max(soundData.offsetTicks(), 0); int delay = Math.max(soundData.offsetTicks(), 0);
BlacksmithVisuals.debug("Playing sound " + soundData.sound() + " after " + delay + " ticks");
Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () -> Bukkit.getScheduler().scheduleSyncDelayedTask(BlacksmithVisuals.getInstance(), () ->
world.playSound(entity, soundData.sound(), soundData.soundCategory(), world.playSound(entity, soundData.sound(), soundData.soundCategory(),
soundData.volume(), soundData.pitch()), delay); soundData.volume(), soundData.pitch()), delay);

View File

@ -1,3 +1,5 @@
# Show debug messages in the console
debug: false
blacksmith: blacksmith:
animation: animation:
# Whether to simulate hitting an anvil or similar by animating the blacksmith's off-hand # Whether to simulate hitting an anvil or similar by animating the blacksmith's off-hand