Factorized key combos

This commit is contained in:
Indyuce 2022-10-16 22:57:27 +02:00
parent fb2cffe57f
commit 3e71ee7d66
3 changed files with 119 additions and 118 deletions

View File

@ -31,10 +31,8 @@ import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.KeyCombo;
import net.Indyuce.mmocore.skill.cast.PlayerKey;
import net.Indyuce.mmocore.skill.cast.ComboMap;
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
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, ClassSkill> skills = new LinkedHashMap<>();
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<>();
@Nullable
private final ComboMap comboMap;
@Deprecated
private final Map<String, EventTrigger> eventTriggers = new HashMap<>();
@ -147,22 +139,14 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
}
// Load different combos
ComboMap comboMap = null;
if (config.contains("key-combos"))
for (String key : config.getConfigurationSection("key-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("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());
comboMap = new ComboMap(config.getConfigurationSection("key-combos"));
} catch (Exception exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load combo map from class '" + id + "': " + exception.getMessage());
}
this.comboMap = comboMap;
if (config.contains("triggers"))
for (String key : config.getConfigurationSection("triggers").getKeys(false))
@ -252,6 +236,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
displayOrder = 0;
expCurve = ExpCurve.DEFAULT;
expTable = null;
comboMap = null;
castParticle = new CastingParticle(Particle.SPELL_INSTANT);
actionBarFormat = "";
this.icon = new ItemStack(material);
@ -446,16 +431,8 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
}
@Nullable
public Map<KeyCombo, Integer> getKeyCombos() {
return combos;
}
public Set<PlayerKey> getFirstComboKeys() {
return firstComboKeys;
}
public int getLongestCombo() {
return longestCombo;
public ComboMap getComboMap() {
return comboMap;
}
@NotNull

View File

@ -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);
}
}

View File

@ -11,10 +11,10 @@ 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 org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -22,30 +22,18 @@ import org.bukkit.event.Listener;
import javax.annotation.Nullable;
import java.util.*;
import java.util.logging.Level;
public class KeyCombos implements Listener {
/**
* 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<>();
private final ComboMap comboMap;
/**
* 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.
* These "starting keys" are saved in {@link #firstComboKeys}
* These "starting keys" are saved in the combo map
*/
@Nullable
private final PlayerKey initializerKey;
private final int longestCombo;
/**
* 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;
public KeyCombos(ConfigurationSection config) {
// 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
comboMap = new ComboMap(config.getConfigurationSection("combos"));
actionBarOptions = config.contains("action-bar") ? new ActionBarOptions(config.getConfigurationSection("action-bar")) : null;
// Load sounds
@ -97,48 +64,55 @@ public class KeyCombos implements Listener {
PlayerData playerData = event.getData();
Player player = playerData.getPlayer();
if (!event.getData().isCasting()) {
if (initializerKey != null) {
// Start combo when there is an initializer key
if (!event.getData().isCasting() && initializerKey != null) {
if (event.getPressed() == initializerKey) {
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
// Start combo
playerData.setSkillCasting(new CustomSkillCastingHandler(playerData));
if (beginComboSound != null)
beginComboSound.playTo(player);
}
return;
} else {
Set<PlayerKey> firstKeys = playerData.getProfess().getFirstComboKeys().isEmpty() ? firstComboKeys : playerData.getProfess().getFirstComboKeys();
if (firstKeys.contains(event.getPressed())) {
}
// Always cancel drop event
if (event.getPressed().equals(PlayerKey.DROP))
event.setCancelled(true);
CustomSkillCastingHandler casting = null;
// Start combo
CustomSkillCastingHandler casting = new CustomSkillCastingHandler(playerData);
// Player is already casting
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);
casting.current.registerKey(event.getPressed());
if (beginComboSound != null)
beginComboSound.playTo(player);
}
return;
}
}
if (casting == null)
return;
// Adding pressed key
CustomSkillCastingHandler casting = (CustomSkillCastingHandler) playerData.getSkillCasting();
casting.current.registerKey(event.getPressed());
casting.onTick();
if (comboClickSound != null)
comboClickSound.playTo(player);
// Always cancel event
// Cancel event if necessary
if (event.getPressed().shouldCancelEvent())
event.setCancelled(true);
// Hash current combo and check
if (casting.classCombos.containsKey(casting.current)) {
int spellSlot = casting.classCombos.get(casting.current) - 1;
if (casting.combos.getCombos().containsKey(casting.current)) {
final int spellSlot = casting.combos.getCombos().get(casting.current) - 1;
playerData.leaveCastingMode();
// Cast spell
@ -150,7 +124,7 @@ public class KeyCombos implements Listener {
}
// Check if current combo is too large
if (casting.current.countKeys() >= casting.classLongestCombo) {
if (casting.current.countKeys() >= casting.combos.getLongest()) {
playerData.leaveCastingMode();
if (failComboSound != null)
failComboSound.playTo(player);
@ -181,25 +155,17 @@ public class KeyCombos implements Listener {
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)
*/
private class CustomSkillCastingHandler extends SkillCastingHandler {
private final KeyCombo current = new KeyCombo();
//Combos used: default combos from the config or the combos defined in the player class.
private final Map<KeyCombo, Integer> classCombos;
private int classLongestCombo;
private final ComboMap combos;
CustomSkillCastingHandler(PlayerData caster) {
super(caster, 10);
if (!caster.getProfess().getKeyCombos().isEmpty()) {
classCombos = caster.getProfess().getKeyCombos();
classLongestCombo = caster.getProfess().getLongestCombo();
} else {
classCombos = combos;
classLongestCombo = longestCombo;
}
combos = Objects.requireNonNullElse(caster.getProfess().getComboMap(), comboMap);
}
@Override
@ -210,10 +176,8 @@ public class KeyCombos implements Listener {
else
getCaster().displayActionBar(actionBarOptions.format(this));
}
}
private class ActionBarOptions {
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.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.isSubtitle = config.getBoolean("" + "", false);
this.isSubtitle = config.getBoolean("is-subtitle", false);
for (PlayerKey key : PlayerKey.values())
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)));
// All remaining
for (; j < casting.classLongestCombo; j++)
for (; j < casting.combos.getLongest(); j++)
builder.append(separator + noKey);
builder.append(suffix);