forked from Upstream/mmocore
Factorized key combos
This commit is contained in:
parent
fb2cffe57f
commit
3e71ee7d66
@ -31,10 +31,8 @@ import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
|
|||||||
import net.Indyuce.mmocore.player.stats.StatInfo;
|
import net.Indyuce.mmocore.player.stats.StatInfo;
|
||||||
import net.Indyuce.mmocore.skill.ClassSkill;
|
import net.Indyuce.mmocore.skill.ClassSkill;
|
||||||
import net.Indyuce.mmocore.skill.RegisteredSkill;
|
import net.Indyuce.mmocore.skill.RegisteredSkill;
|
||||||
import net.Indyuce.mmocore.skill.cast.KeyCombo;
|
import net.Indyuce.mmocore.skill.cast.ComboMap;
|
||||||
import net.Indyuce.mmocore.skill.cast.PlayerKey;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.apache.commons.lang.Validate;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
@ -73,17 +71,11 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
private final Map<String, LinearValue> stats = new HashMap<>();
|
private final Map<String, LinearValue> stats = new HashMap<>();
|
||||||
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
|
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
|
||||||
private final List<Subclass> subclasses = new ArrayList<>();
|
private final List<Subclass> subclasses = new ArrayList<>();
|
||||||
|
|
||||||
// If the class redefines its own key combos.
|
|
||||||
private final Map<KeyCombo, Integer> combos = new HashMap<>();
|
|
||||||
|
|
||||||
private final Set<PlayerKey> firstComboKeys= new HashSet<>();
|
|
||||||
|
|
||||||
|
|
||||||
private int longestCombo;
|
|
||||||
|
|
||||||
private final Map<PlayerResource, ResourceRegeneration> resourceHandlers = new HashMap<>();
|
private final Map<PlayerResource, ResourceRegeneration> resourceHandlers = new HashMap<>();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ComboMap comboMap;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private final Map<String, EventTrigger> eventTriggers = new HashMap<>();
|
private final Map<String, EventTrigger> eventTriggers = new HashMap<>();
|
||||||
|
|
||||||
@ -147,22 +139,14 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load different combos
|
// Load different combos
|
||||||
|
ComboMap comboMap = null;
|
||||||
if (config.contains("key-combos"))
|
if (config.contains("key-combos"))
|
||||||
for (String key : config.getConfigurationSection("key-combos").getKeys(false))
|
|
||||||
try {
|
try {
|
||||||
int spellSlot = Integer.valueOf(key);
|
comboMap = new ComboMap(config.getConfigurationSection("key-combos"));
|
||||||
Validate.isTrue(spellSlot >= 0, "Spell slot must be at least 0");
|
} catch (Exception exception) {
|
||||||
Validate.isTrue(!combos.values().contains(spellSlot), "There is already a key combo with the same skill slot");
|
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load combo map from class '" + id + "': " + exception.getMessage());
|
||||||
KeyCombo combo = new KeyCombo();
|
|
||||||
for (String str : config.getStringList("key-combos." + key))
|
|
||||||
combo.registerKey(PlayerKey.valueOf(UtilityMethods.enumName(str)));
|
|
||||||
|
|
||||||
combos.put(combo, spellSlot);
|
|
||||||
firstComboKeys.add(combo.getAt(0));
|
|
||||||
longestCombo = Math.max(longestCombo, combo.countKeys());
|
|
||||||
} catch (RuntimeException exception) {
|
|
||||||
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load key combo '" + key + "': " + exception.getMessage());
|
|
||||||
}
|
}
|
||||||
|
this.comboMap = comboMap;
|
||||||
|
|
||||||
if (config.contains("triggers"))
|
if (config.contains("triggers"))
|
||||||
for (String key : config.getConfigurationSection("triggers").getKeys(false))
|
for (String key : config.getConfigurationSection("triggers").getKeys(false))
|
||||||
@ -252,6 +236,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
displayOrder = 0;
|
displayOrder = 0;
|
||||||
expCurve = ExpCurve.DEFAULT;
|
expCurve = ExpCurve.DEFAULT;
|
||||||
expTable = null;
|
expTable = null;
|
||||||
|
comboMap = null;
|
||||||
castParticle = new CastingParticle(Particle.SPELL_INSTANT);
|
castParticle = new CastingParticle(Particle.SPELL_INSTANT);
|
||||||
actionBarFormat = "";
|
actionBarFormat = "";
|
||||||
this.icon = new ItemStack(material);
|
this.icon = new ItemStack(material);
|
||||||
@ -446,16 +431,8 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Map<KeyCombo, Integer> getKeyCombos() {
|
public ComboMap getComboMap() {
|
||||||
return combos;
|
return comboMap;
|
||||||
}
|
|
||||||
|
|
||||||
public Set<PlayerKey> getFirstComboKeys() {
|
|
||||||
return firstComboKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLongestCombo() {
|
|
||||||
return longestCombo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
package net.Indyuce.mmocore.skill.cast;
|
||||||
|
|
||||||
|
import io.lumine.mythic.lib.UtilityMethods;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ComboMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using instances of KeyCombo as keys work because {@link KeyCombo}
|
||||||
|
* has a working implementation for the hash code method
|
||||||
|
*/
|
||||||
|
private final Map<KeyCombo, Integer> combos = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All the keys that are at the start of a combo.
|
||||||
|
*/
|
||||||
|
private final Set<PlayerKey> firstKeys = new HashSet<>();
|
||||||
|
|
||||||
|
private final int longestCombo;
|
||||||
|
|
||||||
|
public ComboMap(ConfigurationSection config) {
|
||||||
|
|
||||||
|
int currentLongestCombo = 0;
|
||||||
|
for (String key : config.getKeys(false))
|
||||||
|
try {
|
||||||
|
final int spellSlot = Integer.valueOf(key);
|
||||||
|
Validate.isTrue(spellSlot >= 0, "Spell slot must be at least 0");
|
||||||
|
Validate.isTrue(!combos.values().contains(spellSlot), "There is already a key combo with the same skill slot");
|
||||||
|
KeyCombo combo = new KeyCombo();
|
||||||
|
for (String str : config.getStringList("combos." + key))
|
||||||
|
combo.registerKey(PlayerKey.valueOf(UtilityMethods.enumName(str)));
|
||||||
|
|
||||||
|
combos.put(combo, spellSlot);
|
||||||
|
firstKeys.add(combo.getAt(0));
|
||||||
|
currentLongestCombo = Math.max(currentLongestCombo, combo.countKeys());
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
throw new RuntimeException("Could not loading key combo '" + key + "': " + exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.longestCombo = currentLongestCombo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<KeyCombo, Integer> getCombos() {
|
||||||
|
return combos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLongest() {
|
||||||
|
return longestCombo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComboStart(PlayerKey key) {
|
||||||
|
return firstKeys.contains(key);
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,10 @@ import net.Indyuce.mmocore.api.SoundObject;
|
|||||||
import net.Indyuce.mmocore.api.event.PlayerKeyPressEvent;
|
import net.Indyuce.mmocore.api.event.PlayerKeyPressEvent;
|
||||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||||
import net.Indyuce.mmocore.gui.api.item.Placeholders;
|
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.KeyCombo;
|
||||||
import net.Indyuce.mmocore.skill.cast.PlayerKey;
|
import net.Indyuce.mmocore.skill.cast.PlayerKey;
|
||||||
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
|
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
|
||||||
import org.apache.commons.lang.Validate;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -22,30 +22,18 @@ import org.bukkit.event.Listener;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class KeyCombos implements Listener {
|
public class KeyCombos implements Listener {
|
||||||
|
|
||||||
/**
|
private final ComboMap comboMap;
|
||||||
* Using instances of KeyCombo as keys work because
|
|
||||||
* {@link KeyCombo} has a working implementation for the
|
|
||||||
* hash code method
|
|
||||||
*/
|
|
||||||
private final Map<KeyCombo, Integer> combos = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All the keys that are at the start of a combo.
|
|
||||||
*/
|
|
||||||
private final Set<PlayerKey> firstComboKeys = new HashSet<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key players need to press to start a combo. If it's set to
|
* Key players need to press to start a combo. If it's set to
|
||||||
* null then the player can press any key which starts a combo.
|
* null then the player can press any key which starts a combo.
|
||||||
* These "starting keys" are saved in {@link #firstComboKeys}
|
* These "starting keys" are saved in the combo map
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private final PlayerKey initializerKey;
|
private final PlayerKey initializerKey;
|
||||||
private final int longestCombo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the display of the action bar when casting a skill.
|
* Handles the display of the action bar when casting a skill.
|
||||||
@ -58,28 +46,7 @@ public class KeyCombos implements Listener {
|
|||||||
private final SoundObject beginComboSound, comboClickSound, failComboSound;
|
private final SoundObject beginComboSound, comboClickSound, failComboSound;
|
||||||
|
|
||||||
public KeyCombos(ConfigurationSection config) {
|
public KeyCombos(ConfigurationSection config) {
|
||||||
|
comboMap = new ComboMap(config.getConfigurationSection("combos"));
|
||||||
// Load different combos
|
|
||||||
int currentLongestCombo = 0;
|
|
||||||
for (String key : config.getConfigurationSection("combos").getKeys(false))
|
|
||||||
try {
|
|
||||||
int spellSlot = Integer.valueOf(key);
|
|
||||||
Validate.isTrue(spellSlot >= 0, "Spell slot must be at least 0");
|
|
||||||
Validate.isTrue(!combos.values().contains(spellSlot), "There is already a key combo with the same skill slot");
|
|
||||||
KeyCombo combo = new KeyCombo();
|
|
||||||
for (String str : config.getStringList("combos." + key))
|
|
||||||
combo.registerKey(PlayerKey.valueOf(UtilityMethods.enumName(str)));
|
|
||||||
|
|
||||||
combos.put(combo, spellSlot);
|
|
||||||
firstComboKeys.add(combo.getAt(0));
|
|
||||||
currentLongestCombo = Math.max(currentLongestCombo, combo.countKeys());
|
|
||||||
} catch (RuntimeException exception) {
|
|
||||||
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load key combo '" + key + "': " + exception.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.longestCombo = currentLongestCombo;
|
|
||||||
|
|
||||||
// Load player key names
|
|
||||||
actionBarOptions = config.contains("action-bar") ? new ActionBarOptions(config.getConfigurationSection("action-bar")) : null;
|
actionBarOptions = config.contains("action-bar") ? new ActionBarOptions(config.getConfigurationSection("action-bar")) : null;
|
||||||
|
|
||||||
// Load sounds
|
// Load sounds
|
||||||
@ -97,48 +64,55 @@ public class KeyCombos implements Listener {
|
|||||||
PlayerData playerData = event.getData();
|
PlayerData playerData = event.getData();
|
||||||
Player player = playerData.getPlayer();
|
Player player = playerData.getPlayer();
|
||||||
|
|
||||||
if (!event.getData().isCasting()) {
|
// Start combo when there is an initializer key
|
||||||
if (initializerKey != null) {
|
if (!event.getData().isCasting() && initializerKey != null) {
|
||||||
if (event.getPressed() == initializerKey) {
|
if (event.getPressed() == initializerKey) {
|
||||||
|
|
||||||
|
// Cancel event if necessary
|
||||||
|
if (event.getPressed().shouldCancelEvent())
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
// Start combo
|
// Start combo
|
||||||
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
|
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
|
||||||
if (beginComboSound != null)
|
if (beginComboSound != null)
|
||||||
beginComboSound.playTo(player);
|
beginComboSound.playTo(player);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
Set<PlayerKey> firstKeys = playerData.getProfess().getFirstComboKeys().isEmpty() ? firstComboKeys : playerData.getProfess().getFirstComboKeys();
|
|
||||||
if (firstKeys.contains(event.getPressed())) {
|
|
||||||
|
|
||||||
// Always cancel drop event
|
CustomSkillCastingHandler casting = null;
|
||||||
if (event.getPressed().equals(PlayerKey.DROP))
|
|
||||||
event.setCancelled(true);
|
|
||||||
|
|
||||||
// Start combo
|
// Player is already casting
|
||||||
CustomSkillCastingHandler casting = new CustomSkillCastingHandler(playerData);
|
if (event.getData().isCasting())
|
||||||
|
casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
|
||||||
|
|
||||||
|
// Start combo when there is NO initializer key
|
||||||
|
else {
|
||||||
|
final ComboMap comboMap = Objects.requireNonNullElse(playerData.getProfess().getComboMap(), this.comboMap);
|
||||||
|
if (comboMap.isComboStart(event.getPressed())) {
|
||||||
|
casting = new CustomSkillCastingHandler(playerData);
|
||||||
playerData.setSkillCasting(casting);
|
playerData.setSkillCasting(casting);
|
||||||
casting.current.registerKey(event.getPressed());
|
|
||||||
if (beginComboSound != null)
|
if (beginComboSound != null)
|
||||||
beginComboSound.playTo(player);
|
beginComboSound.playTo(player);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (casting == null)
|
||||||
|
return;
|
||||||
|
|
||||||
// Adding pressed key
|
// Adding pressed key
|
||||||
CustomSkillCastingHandler casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
|
|
||||||
casting.current.registerKey(event.getPressed());
|
casting.current.registerKey(event.getPressed());
|
||||||
casting.onTick();
|
casting.onTick();
|
||||||
if (comboClickSound != null)
|
if (comboClickSound != null)
|
||||||
comboClickSound.playTo(player);
|
comboClickSound.playTo(player);
|
||||||
|
|
||||||
// Always cancel event
|
// Cancel event if necessary
|
||||||
|
if (event.getPressed().shouldCancelEvent())
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
// Hash current combo and check
|
// Hash current combo and check
|
||||||
if (casting.classCombos.containsKey(casting.current)) {
|
if (casting.combos.getCombos().containsKey(casting.current)) {
|
||||||
int spellSlot = casting.classCombos.get(casting.current) - 1;
|
final int spellSlot = casting.combos.getCombos().get(casting.current) - 1;
|
||||||
playerData.leaveCastingMode();
|
playerData.leaveCastingMode();
|
||||||
|
|
||||||
// Cast spell
|
// Cast spell
|
||||||
@ -150,7 +124,7 @@ public class KeyCombos implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if current combo is too large
|
// Check if current combo is too large
|
||||||
if (casting.current.countKeys() >= casting.classLongestCombo) {
|
if (casting.current.countKeys() >= casting.combos.getLongest()) {
|
||||||
playerData.leaveCastingMode();
|
playerData.leaveCastingMode();
|
||||||
if (failComboSound != null)
|
if (failComboSound != null)
|
||||||
failComboSound.playTo(player);
|
failComboSound.playTo(player);
|
||||||
@ -181,25 +155,17 @@ public class KeyCombos implements Listener {
|
|||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
private class CustomSkillCastingHandler extends SkillCastingHandler {
|
||||||
private final KeyCombo current = new KeyCombo();
|
private final KeyCombo current = new KeyCombo();
|
||||||
//Combos used: default combos from the config or the combos defined in the player class.
|
private final ComboMap combos;
|
||||||
private final Map<KeyCombo, Integer> classCombos;
|
|
||||||
private int classLongestCombo;
|
|
||||||
|
|
||||||
CustomSkillCastingHandler(PlayerData caster) {
|
CustomSkillCastingHandler(PlayerData caster) {
|
||||||
super(caster, 10);
|
super(caster, 10);
|
||||||
if (!caster.getProfess().getKeyCombos().isEmpty()) {
|
|
||||||
classCombos = caster.getProfess().getKeyCombos();
|
combos = Objects.requireNonNullElse(caster.getProfess().getComboMap(), comboMap);
|
||||||
classLongestCombo = caster.getProfess().getLongestCombo();
|
|
||||||
} else {
|
|
||||||
classCombos = combos;
|
|
||||||
classLongestCombo = longestCombo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -210,10 +176,8 @@ public class KeyCombos implements Listener {
|
|||||||
else
|
else
|
||||||
getCaster().displayActionBar(actionBarOptions.format(this));
|
getCaster().displayActionBar(actionBarOptions.format(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class ActionBarOptions {
|
private class ActionBarOptions {
|
||||||
private final String separator, noKey, prefix, suffix;
|
private final String separator, noKey, prefix, suffix;
|
||||||
|
|
||||||
@ -229,7 +193,7 @@ public class KeyCombos implements Listener {
|
|||||||
this.suffix = config.contains("suffix") ? config.getString("suffix") : "";
|
this.suffix = config.contains("suffix") ? config.getString("suffix") : "";
|
||||||
this.separator = Objects.requireNonNull(config.getString("separator"), "Could not find action bar option 'separator'");
|
this.separator = Objects.requireNonNull(config.getString("separator"), "Could not find action bar option 'separator'");
|
||||||
this.noKey = Objects.requireNonNull(config.getString("no-key"), "Could not find action bar option 'no-key'");
|
this.noKey = Objects.requireNonNull(config.getString("no-key"), "Could not find action bar option 'no-key'");
|
||||||
this.isSubtitle = config.getBoolean("" + "", false);
|
this.isSubtitle = config.getBoolean("is-subtitle", false);
|
||||||
for (PlayerKey key : PlayerKey.values())
|
for (PlayerKey key : PlayerKey.values())
|
||||||
keyNames.put(key, Objects.requireNonNull(config.getString("key-name." + key.name()), "Could not find translation for key " + key.name()));
|
keyNames.put(key, Objects.requireNonNull(config.getString("key-name." + key.name()), "Could not find translation for key " + key.name()));
|
||||||
}
|
}
|
||||||
@ -246,7 +210,7 @@ public class KeyCombos implements Listener {
|
|||||||
builder.append(separator + keyNames.get(casting.current.getAt(j)));
|
builder.append(separator + keyNames.get(casting.current.getAt(j)));
|
||||||
|
|
||||||
// All remaining
|
// All remaining
|
||||||
for (; j < casting.classLongestCombo; j++)
|
for (; j < casting.combos.getLongest(); j++)
|
||||||
builder.append(separator + noKey);
|
builder.append(separator + noKey);
|
||||||
|
|
||||||
builder.append(suffix);
|
builder.append(suffix);
|
||||||
|
Loading…
Reference in New Issue
Block a user