API method to force into skill casting

This commit is contained in:
Jules 2023-05-07 09:33:18 +02:00
parent 590801203d
commit 09d76dab1b
9 changed files with 163 additions and 94 deletions

View File

@ -110,6 +110,7 @@ public class MMOCore extends JavaPlugin {
@Override
public void onLoad() {
getLogger().log(Level.INFO, "Plugin file is called '" + getFile().getName() + "'");
// Register MMOCore-specific objects
MythicLib.plugin.getEntities().registerRelationHandler(new PartyRelationHandler());
@ -238,7 +239,8 @@ public class MMOCore extends JavaPlugin {
// Skill casting
try {
SkillCastingMode mode = SkillCastingMode.valueOf(UtilityMethods.enumName(getConfig().getString("skill-casting.mode")));
Bukkit.getPluginManager().registerEvents(mode.loadFromConfig(getConfig().getConfigurationSection("skill-casting")), this);
mode.setCurrent(getConfig().getConfigurationSection("skill-casting"));
} catch (RuntimeException exception) {
getLogger().log(Level.WARNING, "Could not load skill casting: " + exception.getMessage());
}

View File

@ -46,7 +46,8 @@ import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import net.Indyuce.mmocore.skilltree.IntegerCoordinates;
import net.Indyuce.mmocore.skilltree.NodeStatus;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
@ -88,7 +89,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/
private double health;
private Guild guild;
private SkillCastingHandler skillCasting;
private SkillCastingInstance skillCasting;
private final PlayerQuests questData;
private final PlayerStats playerStats;
private final List<UUID> friends = new ArrayList<>();
@ -99,7 +100,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated
private final Set<String> waypoints = new HashSet<>();
private final Map<String, Integer> skills = new HashMap<>();
// TODO change it to an array....... Map<Integer, BoundSkillInfo> is just BoundSkillInfo[]
private final Map<Integer, BoundSkillInfo> boundSkills = new HashMap<>();
private final PlayerProfessions collectSkills = new PlayerProfessions(this);
private final PlayerAttributes attributes = new PlayerAttributes(this);
@ -1019,13 +1019,21 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return skillCasting != null;
}
public void setSkillCasting(SkillCastingHandler skillCasting) {
public void setSkillCasting(@NotNull SkillCastingInstance skillCasting) {
Validate.isTrue(!isCasting(), "Player already in casting mode");
this.skillCasting = skillCasting;
}
/**
* API Method
*/
public void setSkillCasting() {
Validate.isTrue(!isCasting(), "Player already in casting mode");
setSkillCasting(SkillCastingMode.getCurrent().newInstance(this));
}
@NotNull
public SkillCastingHandler getSkillCasting() {
public SkillCastingInstance getSkillCasting() {
return Objects.requireNonNull(skillCasting, "Player not in casting mode");
}

View File

@ -8,13 +8,13 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.scheduler.BukkitRunnable;
public abstract class SkillCastingHandler extends BukkitRunnable implements Listener {
public abstract class SkillCastingInstance extends BukkitRunnable implements Listener {
private final PlayerData caster;
private boolean open = true;
private int j;
public SkillCastingHandler(PlayerData caster, int runnablePeriod) {
public SkillCastingInstance(PlayerData caster, int runnablePeriod) {
this.caster = caster;
runTaskTimer(MMOCore.plugin, 0, runnablePeriod);

View File

@ -0,0 +1,18 @@
package net.Indyuce.mmocore.skill.cast;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
/**
* @apiNote Purely for API
*/
public interface SkillCastingListener extends Listener {
@NotNull
public SkillCastingMode getCastingMode();
@NotNull
public SkillCastingInstance newInstance(@NotNull PlayerData player);
}

View File

@ -1,11 +1,16 @@
package net.Indyuce.mmocore.skill.cast;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.skill.cast.listener.SkillBar;
import net.Indyuce.mmocore.skill.cast.listener.KeyCombos;
import net.Indyuce.mmocore.skill.cast.listener.SkillCastingDisabled;
import net.Indyuce.mmocore.skill.cast.listener.SkillScroller;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import java.util.function.Function;
public enum SkillCastingMode {
@ -23,7 +28,7 @@ public enum SkillCastingMode {
* to navigate through the entire castable skill list. Then press
* one key to cast the one selected.
*/
SKILL_SCROLL(config -> new SkillScroller(config)),
SKILL_SCROLLER(config -> new SkillScroller(config)),
/**
* Initialize your skill combo by pressing some key.
@ -37,8 +42,7 @@ public enum SkillCastingMode {
/**
* Entirely disables skill casting.
*/
NONE(config -> new Listener() {
});
NONE(config -> new SkillCastingDisabled());
/**
* Not implemented yet.
@ -59,13 +63,25 @@ public enum SkillCastingMode {
;
private final Function<ConfigurationSection, Listener> listenerLoader;
private final Function<ConfigurationSection, SkillCastingListener> listenerLoader;
SkillCastingMode(Function<ConfigurationSection, Listener> listenerLoader) {
private static SkillCastingListener current;
SkillCastingMode(Function<ConfigurationSection, SkillCastingListener> listenerLoader) {
this.listenerLoader = listenerLoader;
}
public Listener loadFromConfig(ConfigurationSection config) {
return listenerLoader.apply(config);
public void setCurrent(@NotNull ConfigurationSection config) {
Validate.isTrue(current == null, "Skill casting mode already initialized");
current = listenerLoader.apply(config);
if (this == NONE) return;
// Register listener
Bukkit.getPluginManager().registerEvents(current, MMOCore.plugin);
}
@NotNull
public static SkillCastingListener getCurrent() {
return Objects.requireNonNull(current, "Skill casting mode hasn't been initialized yet");
}
}

View File

@ -11,10 +11,7 @@ import net.Indyuce.mmocore.api.SoundObject;
import net.Indyuce.mmocore.api.event.PlayerKeyPressEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.skill.cast.ComboMap;
import net.Indyuce.mmocore.skill.cast.KeyCombo;
import net.Indyuce.mmocore.skill.cast.PlayerKey;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.skill.cast.*;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -24,7 +21,7 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.*;
public class KeyCombos implements Listener {
public class KeyCombos implements SkillCastingListener {
private final ComboMap comboMap;
@ -56,8 +53,17 @@ public class KeyCombos implements Listener {
failComboSound = config.contains("sound.fail-combo") ? new SoundObject(config.getConfigurationSection("sound.fail-combo")) : null;
// Find initializer key
initializerKey = config.contains("initializer-key") ? PlayerKey.valueOf(UtilityMethods.enumName(Objects.requireNonNull(
config.getString("initializer-key"), "Could not find initializer key"))) : null;
initializerKey = config.contains("initializer-key") ? PlayerKey.valueOf(UtilityMethods.enumName(Objects.requireNonNull(config.getString("initializer-key"), "Could not find initializer key"))) : null;
}
@Override
public SkillCastingInstance newInstance(@NotNull PlayerData player) {
return new CustomSkillCastingInstance(player);
}
@Override
public SkillCastingMode getCastingMode() {
return SkillCastingMode.KEY_COMBOS;
}
@EventHandler
@ -70,46 +76,39 @@ public class KeyCombos implements Listener {
if (event.getPressed() == initializerKey) {
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
// Start combo
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
if (beginComboSound != null)
beginComboSound.playTo(player);
playerData.setSkillCasting(new CustomSkillCastingInstance(playerData));
if (beginComboSound != null) beginComboSound.playTo(player);
}
return;
}
@Nullable CustomSkillCastingHandler casting = null;
@Nullable CustomSkillCastingInstance casting = null;
// Player is already casting
if (event.getData().isCasting())
casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
if (event.getData().isCasting()) casting = (CustomSkillCastingInstance) playerData.getSkillCasting();
// Start combo when there is NO initializer key
else {
final @NotNull ComboMap comboMap = Objects.requireNonNullElse(playerData.getProfess().getComboMap(), this.comboMap);
if (comboMap.isComboStart(event.getPressed())) {
casting = new CustomSkillCastingHandler(playerData);
casting = new CustomSkillCastingInstance(playerData);
playerData.setSkillCasting(casting);
if (beginComboSound != null)
beginComboSound.playTo(player);
if (beginComboSound != null) beginComboSound.playTo(player);
}
}
if (casting == null)
return;
if (casting == null) return;
// Adding pressed key
casting.current.registerKey(event.getPressed());
casting.onTick();
if (comboClickSound != null)
comboClickSound.playTo(player);
if (comboClickSound != null) comboClickSound.playTo(player);
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
// Hash current combo and check
if (casting.combos.getCombos().containsKey(casting.current)) {
@ -127,8 +126,7 @@ public class KeyCombos implements Listener {
// Check if current combo is too large
if (casting.current.countKeys() >= casting.combos.getLongest()) {
playerData.leaveSkillCasting();
if (failComboSound != null)
failComboSound.playTo(player);
if (failComboSound != null) failComboSound.playTo(player);
}
}
@ -157,13 +155,14 @@ public class KeyCombos implements Listener {
}
/**
* Loads the player current combos & the combos applicable to the player (combos defined in its class or the default combos of the config.yml)
* Loads the player current combos & the combos applicable to the player
* (combos defined in its class or the default combos of the config.yml)
*/
private class CustomSkillCastingHandler extends SkillCastingHandler {
public class CustomSkillCastingInstance extends SkillCastingInstance {
private final KeyCombo current = new KeyCombo();
private final ComboMap combos;
CustomSkillCastingHandler(PlayerData caster) {
CustomSkillCastingInstance(PlayerData caster) {
super(caster, 10);
combos = Objects.requireNonNullElse(caster.getProfess().getComboMap(), comboMap);
@ -171,11 +170,9 @@ public class KeyCombos implements Listener {
@Override
public void onTick() {
if (actionBarOptions != null)
if (actionBarOptions.isSubtitle)
getCaster().getPlayer().sendTitle(" ", actionBarOptions.format(this), 0, 20, 0);
else
getCaster().displayActionBar(actionBarOptions.format(this));
if (actionBarOptions != null) if (actionBarOptions.isSubtitle)
getCaster().getPlayer().sendTitle(" ", actionBarOptions.format(this), 0, 20, 0);
else getCaster().displayActionBar(actionBarOptions.format(this));
}
}
@ -199,7 +196,7 @@ public class KeyCombos implements Listener {
keyNames.put(key, Objects.requireNonNull(config.getString("key-name." + key.name()), "Could not find translation for key " + key.name()));
}
public String format(CustomSkillCastingHandler casting) {
public String format(CustomSkillCastingInstance casting) {
StringBuilder builder = new StringBuilder();
Placeholders holders = MMOCore.plugin.actionBarManager.getActionBarPlaceholders(casting.getCaster());

View File

@ -10,8 +10,9 @@ import net.Indyuce.mmocore.api.event.PlayerKeyPressEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.cast.PlayerKey;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import org.bukkit.Bukkit;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingListener;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import org.bukkit.GameMode;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
@ -19,10 +20,11 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class SkillBar implements Listener {
public class SkillBar implements SkillCastingListener {
private final PlayerKey mainKey;
private final boolean disableSneak;
@ -31,6 +33,16 @@ public class SkillBar implements Listener {
disableSneak = config.getBoolean("disable-sneak");
}
@Override
public SkillCastingInstance newInstance(@NotNull PlayerData player) {
return new CustomSkillCastingInstance(player);
}
@Override
public SkillCastingMode getCastingMode() {
return SkillCastingMode.SKILL_BAR;
}
@EventHandler
public void enterSkillCasting(PlayerKeyPressEvent event) {
if (event.getPressed() != mainKey) return;
@ -44,14 +56,13 @@ public class SkillBar implements Listener {
// Enter spell casting
final PlayerData playerData = event.getData();
if (player.getGameMode() != GameMode.SPECTATOR && (MMOCore.plugin.configManager.canCreativeCast || player.getGameMode() != GameMode.CREATIVE) && !playerData.isCasting() && !playerData.getBoundSkills()
.isEmpty()) {
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
if (player.getGameMode() != GameMode.SPECTATOR && (MMOCore.plugin.configManager.canCreativeCast || player.getGameMode() != GameMode.CREATIVE) && !playerData.isCasting() && !playerData.getBoundSkills().isEmpty()) {
playerData.setSkillCasting(new CustomSkillCastingInstance(playerData));
MMOCore.plugin.soundManager.getSound(SoundEvent.SPELL_CAST_BEGIN).playTo(player);
}
}
private class CustomSkillCastingHandler extends SkillCastingHandler {
public class CustomSkillCastingInstance extends SkillCastingInstance {
private final String ready = MMOCore.plugin.configManager.getSimpleMessage("casting.action-bar.ready").message();
private final String onCooldown = MMOCore.plugin.configManager.getSimpleMessage("casting.action-bar.on-cooldown").message();
private final String noMana = MMOCore.plugin.configManager.getSimpleMessage("casting.action-bar.no-mana").message();
@ -60,7 +71,7 @@ public class SkillBar implements Listener {
private int j;
CustomSkillCastingHandler(PlayerData playerData) {
CustomSkillCastingInstance(PlayerData playerData) {
super(playerData, 1);
}
@ -119,11 +130,7 @@ public class SkillBar implements Listener {
if (!data.isOnline()) return str.toString();
for (int slot : data.mapBoundSkills().keySet()) {
ClassSkill skill = data.getBoundSkill(slot);
str.append(str.isEmpty() ? "" : split).append((onCooldown(data, skill) ? onCooldown.replace("{cooldown}",
String.valueOf(data.getCooldownMap().getInfo(skill).getRemaining() / 1000)) : noMana(data, skill) ? noMana : (noStamina(
data, skill) ? noStamina : ready)).replace("{index}",
String.valueOf(slot + (data.getPlayer().getInventory().getHeldItemSlot() < slot ? 1 : 0)))
.replace("{skill}", data.getBoundSkill(slot).getSkill().getName()));
str.append(str.isEmpty() ? "" : split).append((onCooldown(data, skill) ? onCooldown.replace("{cooldown}", String.valueOf(data.getCooldownMap().getInfo(skill).getRemaining() / 1000)) : noMana(data, skill) ? noMana : (noStamina(data, skill) ? noStamina : ready)).replace("{index}", String.valueOf(slot + (data.getPlayer().getInventory().getHeldItemSlot() < slot ? 1 : 0))).replace("{skill}", data.getBoundSkill(slot).getSkill().getName()));
}
return MMOCore.plugin.placeholderParser.parse(data.getPlayer(), str.toString());
}
@ -142,8 +149,7 @@ public class SkillBar implements Listener {
}
private boolean noStamina(PlayerData data, ClassSkill skill) {
return skill.getSkill().hasModifier("stamina") && skill.getModifier("stamina",
data.getSkillLevel(skill.getSkill())) > data.getStamina();
return skill.getSkill().hasModifier("stamina") && skill.getModifier("stamina", data.getSkillLevel(skill.getSkill())) > data.getStamina();
}
@Override

View File

@ -0,0 +1,20 @@
package net.Indyuce.mmocore.skill.cast.listener;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingListener;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import org.jetbrains.annotations.NotNull;
public class SkillCastingDisabled implements SkillCastingListener {
@Override
public SkillCastingInstance newInstance(@NotNull PlayerData player) {
throw new RuntimeException("Skill casting is disabled");
}
@Override
public SkillCastingMode getCastingMode() {
return SkillCastingMode.NONE;
}
}

View File

@ -8,17 +8,19 @@ import net.Indyuce.mmocore.api.SoundObject;
import net.Indyuce.mmocore.api.event.PlayerKeyPressEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.cast.PlayerKey;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingListener;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.Objects;
public class SkillScroller implements Listener {
public class SkillScroller implements SkillCastingListener {
/**
* Key players need to press to start casting
@ -40,6 +42,16 @@ public class SkillScroller implements Listener {
castKey = PlayerKey.valueOf(UtilityMethods.enumName(Objects.requireNonNull(config.getString("cast-key"), "Could not find cast key")));
}
@Override
public SkillCastingInstance newInstance(@NotNull PlayerData player) {
return new CustomSkillCastingInstance(player);
}
@Override
public SkillCastingMode getCastingMode() {
return SkillCastingMode.SKILL_SCROLLER;
}
@EventHandler
public void whenPressingKey(PlayerKeyPressEvent event) {
PlayerData playerData = event.getData();
@ -51,36 +63,30 @@ public class SkillScroller implements Listener {
if (playerData.isCasting()) {
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
playerData.leaveSkillCasting();
if (leaveSound != null)
leaveSound.playTo(player);
if (leaveSound != null) leaveSound.playTo(player);
return;
}
// Check if there are skills bound
if (playerData.getBoundSkills().isEmpty())
return;
if (playerData.getBoundSkills().isEmpty()) return;
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
// Enter casting mode
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
if (enterSound != null)
enterSound.playTo(player);
playerData.setSkillCasting(new CustomSkillCastingInstance(playerData));
if (enterSound != null) enterSound.playTo(player);
}
if (event.getPressed() == castKey && playerData.isCasting()) {
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
CustomSkillCastingHandler casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
CustomSkillCastingInstance casting = (CustomSkillCastingInstance) playerData.getSkillCasting();
PlayerMetadata caster = playerData.getMMOPlayerData().getStatMap().cache(EquipmentSlot.MAIN_HAND);
playerData.getBoundSkill(casting.index).toCastable(playerData).cast(new TriggerMetadata(caster, null, null));
}
@ -89,8 +95,7 @@ public class SkillScroller implements Listener {
@EventHandler
public void onScroll(PlayerItemHeldEvent event) {
PlayerData playerData = PlayerData.get(event.getPlayer());
if (!playerData.isCasting())
return;
if (!playerData.isCasting()) return;
if (playerData.getBoundSkills().isEmpty()) {
playerData.leaveSkillCasting();
@ -104,29 +109,26 @@ public class SkillScroller implements Listener {
int change = Math.abs(dist1) < Math.abs(dist2) ? (Math.abs(dist1) < Math.abs(dist3) ? dist1 : dist3) : (Math.abs(dist3) < Math.abs(dist2) ? dist3 : dist2);
// Scroll trough items
CustomSkillCastingHandler casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
CustomSkillCastingInstance casting = (CustomSkillCastingInstance) playerData.getSkillCasting();
casting.index = mod(casting.index + change, playerData.getBoundSkills().size());
casting.onTick();
if (changeSound != null)
changeSound.playTo(event.getPlayer());
if (changeSound != null) changeSound.playTo(event.getPlayer());
}
private int mod(int x, int n) {
while (x < 0)
x += n;
while (x < 0) x += n;
while (x >= n)
x -= n;
while (x >= n) x -= n;
return x;
}
private class CustomSkillCastingHandler extends SkillCastingHandler {
public class CustomSkillCastingInstance extends SkillCastingInstance {
private int index = 0;
CustomSkillCastingHandler(PlayerData caster) {
CustomSkillCastingInstance(PlayerData caster) {
super(caster, 10);
}