Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ka0rX 2023-07-09 16:10:34 +01:00
commit e0bdfa2000
25 changed files with 213 additions and 171 deletions

View File

@ -46,8 +46,8 @@ import net.Indyuce.mmocore.skill.binding.BoundSkillInfo;
import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import net.Indyuce.mmocore.skilltree.SkillTreeStatus;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.SkillTreeStatus;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
@ -351,7 +351,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
/**
* @return If the item is unlocked by the player
* This is used for skills that can be locked & unlocked.
* This is used for skills that can be locked & unlocked.
*/
public boolean hasUnlocked(Unlockable unlockable) {
return unlockable.isUnlockedByDefault() || unlockedItems.contains(unlockable.getUnlockNamespacedKey());
@ -745,6 +745,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
final int y = getPlayer().getLocation().getBlockY();
final int z = getPlayer().getLocation().getBlockZ();
final int warpTime = target.getWarpTime();
final boolean hasPerm = getPlayer().hasPermission("mmocore.bypass-waypoint-wait");
int t;
public void run() {
@ -757,7 +758,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
}
MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", String.valueOf((warpTime - t) / 20)).send(getPlayer());
if (t++ >= warpTime) {
if (hasPerm || t++ >= warpTime) {
getPlayer().teleport(target.getLocation());
getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_TELEPORT).playTo(getPlayer());
@ -1003,29 +1004,30 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return skillCasting != null;
}
/**
* @return true if the PlayerEnterCastingModeEvent successfully put the player into casting mode, otherwise if the event is cancelled, returns false.
* @apiNote Changed to a boolean to reflect the cancellation state of the event being fired
*/
@Deprecated
public boolean setSkillCasting(@NotNull SkillCastingInstance skillCasting) {
Validate.isTrue(!isCasting(), "Player already in casting mode");
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
if (event.isCancelled()){
skillCasting.close();
return false;
}
this.skillCasting = skillCasting;
skillCasting.close();
setSkillCasting();
return true;
}
/**
* API Method
* @return true if the PlayerEnterCastingModeEvent successfully put the player into casting mode, otherwise if the event is cancelled, returns false.
* @apiNote Changed to a boolean to reflect the cancellation state of the event being fired
*/
public void setSkillCasting() {
public boolean setSkillCasting() {
Validate.isTrue(!isCasting(), "Player already in casting mode");
setSkillCasting(SkillCastingMode.getCurrent().newInstance(this));
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
this.skillCasting = SkillCastingMode.getCurrent().newInstance(this);
return true;
}
@NotNull
@ -1035,27 +1037,25 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
/**
* API Method to leave casting mode and fire the PlayerExitCastingModeEvent
*
* @return true if the skill casting mode was left, or false if the event was cancelled, keeping the player in casting mode.
*/
public boolean leaveSkillCasting(){
return this.leaveSkillCasting(false);
public boolean leaveSkillCasting() {
return leaveSkillCasting(false);
}
/**
* @param skipEvent Skip Firing the PlayerExitCastingModeEvent
* @return true if the PlayerExitCastingModeEvent is not cancelled, or if the event is skipped.
*
*/
public boolean leaveSkillCasting(boolean skipEvent) {
Validate.isTrue(isCasting(), "Player not in casting mode");
if (!skipEvent) {
PlayerExitCastingModeEvent event = new PlayerExitCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
if (event.isCancelled()) return false;
}
skillCasting.close();
this.skillCasting = null;
setLastActivity(PlayerActivity.ACTION_BAR_MESSAGE, 0); // Reset action bar
@ -1221,7 +1221,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* checks if they could potentially upgrade to one of these
*
* @return If the player can change its current class to
* a subclass
* a subclass
*/
@Deprecated
public boolean canChooseSubclass() {

View File

@ -1,9 +1,10 @@
package net.Indyuce.mmocore.api.player.attribute;
import io.lumine.mythic.lib.api.stat.StatMap;
import io.lumine.mythic.lib.api.stat.StatInstance;
import io.lumine.mythic.lib.api.stat.handler.StatHandler;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.configuration.ConfigurationSection;
/**
* This fixes an issue where registering new stat modifiers in ML
@ -13,17 +14,13 @@ import net.Indyuce.mmocore.api.player.PlayerData;
* This stat handler MAY call subsequent stat handlers. There might
* be infinite recursion problems if another attr. grants extra attribute pts.
*/
public class MMOCoreAttributeStatHandler implements StatHandler {
public class MMOCoreAttributeStatHandler extends StatHandler {
private final PlayerAttribute attr;
private final String statName;
public MMOCoreAttributeStatHandler(PlayerAttribute attr) {
public MMOCoreAttributeStatHandler(ConfigurationSection config, PlayerAttribute attr) {
super(config, "ADDITIONAL_" + attr.getId().toUpperCase().replace("-", "_"));
this.attr = attr;
this.statName = "ADDITIONAL_" + attr.getId().toUpperCase().replace("-", "_");
}
public String getStat() {
return statName;
}
/**
@ -31,22 +28,12 @@ public class MMOCoreAttributeStatHandler implements StatHandler {
* is not loaded yet, hence the try/catch clause
*/
@Override
public void runUpdate(StatMap statMap) {
public void runUpdate(StatInstance instance) {
try {
final PlayerData playerData = MMOCore.plugin.dataProvider.getDataManager().get(statMap.getPlayerData().getUniqueId());
final PlayerData playerData = MMOCore.plugin.dataProvider.getDataManager().get(instance.getMap().getPlayerData().getUniqueId());
playerData.getAttributes().getInstance(attr).updateStats();
} catch (NullPointerException exception) {
// Player data is not loaded yet so there's nothing to update.
}
}
@Override
public double getBaseValue(StatMap statMap) {
return 0;
}
@Override
public double getTotalValue(StatMap statMap) {
return statMap.getStat(statName);
}
}

View File

@ -222,7 +222,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
for (String key : config.getStringList("main-exp-sources"))
try {
MMOCore.plugin.experience.registerSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), this));
} catch (IllegalArgumentException exception) {
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp source '" + key + "' from class '"
+ id + "': " + exception.getMessage());
}

View File

@ -39,8 +39,14 @@ public class MMOCoreUtils {
: caseOnWords(item.getType().name().replace("_", " "));
}
/**
* @param current Current value of resource
* @param maxStat Maximum value of resource
* @return Clamped resource value. If the provided current value is 0,
* this function will return the maximum resource value.
*/
public static double fixResource(double current, double maxStat) {
return current == 0 ? maxStat : Math.min(current, maxStat);
return current == 0 ? maxStat : Math.max(0, Math.min(current, maxStat));
}
public static String caseOnWords(String s) {
@ -62,7 +68,6 @@ public class MMOCoreUtils {
}
/**
*
* @param value an integer you want to convert
* @return the string representing the integer but with roman letters
*/
@ -82,23 +87,25 @@ public class MMOCoreUtils {
roman_numerals.put("IV", 4);
roman_numerals.put("I", 1);
String res = "";
for(Map.Entry<String, Integer> entry : roman_numerals.entrySet()){
int matches = value/entry.getValue();
for (Map.Entry<String, Integer> entry : roman_numerals.entrySet()) {
int matches = value / entry.getValue();
res += repeat(entry.getKey(), matches);
value = value % entry.getValue();
}
return res;
}
private static String repeat(String s, int n) {
if(s == null) {
if (s == null) {
return null;
}
final StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
for (int i = 0; i < n; i++) {
sb.append(s);
}
return sb.toString();
}
/**
* Displays an in game indicator using a hologram. This uses
* LumineUtils hologramFactory to summon holograms
@ -260,8 +267,9 @@ public class MMOCoreUtils {
* @param damage Damage that needs to be applied
*/
public static void decreaseDurability(Player player, EquipmentSlot slot, int damage) {
ItemStack item = player.getInventory().getItem(slot);
if (item == null || item.getType().getMaxDurability() == 0 || !item.hasItemMeta() || !(item.getItemMeta() instanceof Damageable) || item.getItemMeta().isUnbreakable())
if (item == null || item.getType().getMaxDurability() == 0 || item.getItemMeta().isUnbreakable())
return;
PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, item, damage);
@ -270,11 +278,12 @@ public class MMOCoreUtils {
return;
ItemMeta meta = item.getItemMeta();
if (event.getDamage() + ((Damageable) meta).getDamage() >= item.getType().getMaxDurability()) {
final int newDamage = event.getDamage() + ((Damageable) meta).getDamage();
if (newDamage >= item.getType().getMaxDurability()) {
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1F, 1F);
player.getInventory().setItem(slot, null);
} else {
((Damageable) meta).setDamage(((Damageable) meta).getDamage() + event.getDamage());
((Damageable) meta).setDamage(newDamage);
item.setItemMeta(meta);
}
}

View File

@ -2,7 +2,8 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.event.PlayerKillEntityEvent;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.util.FlushableRegistry;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
@ -15,9 +16,11 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.persistence.PersistentDataType;
import javax.annotation.Nullable;
import java.util.UUID;
public class KillMobExperienceSource extends SpecificExperienceSource<Entity> {
private final EntityType type;
@ -37,17 +40,36 @@ public class KillMobExperienceSource extends SpecificExperienceSource<Entity> {
public ExperienceSourceManager<KillMobExperienceSource> newManager() {
return new ExperienceSourceManager<KillMobExperienceSource>() {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void a(PlayerKillEntityEvent event) {
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, () -> {
if (event.getTarget().isDead() && !event.getTarget().getPersistentDataContainer().has(new NamespacedKey(MMOCore.plugin, "spawner_spawned"), PersistentDataType.STRING)) {
PlayerData data = PlayerData.get(event.getPlayer());
/**
* This map is used to keep track of the last player who
* hit some entity. It is flushed on entity death.
*/
private final FlushableRegistry<UUID, UUID> registry = new FlushableRegistry<>((entity, attacker) -> Bukkit.getEntity(entity) == null, 20 * 60);
for (KillMobExperienceSource source : getSources())
if (source.matches(data, event.getTarget()))
source.giveExperience(data, 1, MMOCoreUtils.getCenterLocation(event.getTarget()));
}
}, 2);
@Override
public void whenClosed() {
registry.close();
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void registerLastAttacker(PlayerAttackEvent event) {
registry.getRegistry().put(event.getEntity().getUniqueId(), event.getAttacker().getData().getUniqueId());
}
@EventHandler(priority = EventPriority.MONITOR)
public void giveExp(EntityDeathEvent event) {
// Always remove entry from map
final @Nullable UUID lastAttacker = this.registry.getRegistry().remove(event.getEntity().getUniqueId());
if (lastAttacker == null) return;
if (event.getEntity().getPersistentDataContainer().has(new NamespacedKey(MMOCore.plugin, "spawner_spawned"), PersistentDataType.STRING))
return;
final PlayerData data = PlayerData.get(lastAttacker);
for (KillMobExperienceSource source : getSources())
if (source.matches(data, event.getEntity()))
source.giveExperience(data, 1, MMOCoreUtils.getCenterLocation(event.getEntity()));
}
};
}

View File

@ -8,18 +8,17 @@ import org.bukkit.block.Biome;
import io.lumine.mythic.lib.api.MMOLineConfig;
public class BiomeCondition extends Condition {
private final List<String> names;
private final List<String> names;
public BiomeCondition(MMOLineConfig config) {
super(config);
public BiomeCondition(MMOLineConfig config) {
super(config);
config.validate("name");
names = Arrays.asList(config.getString("name").toUpperCase().split(","));
}
config.validate("name");
names = Arrays.asList(config.getString("name").toUpperCase().split(","));
}
@Override
public boolean isMet(ConditionInstance entity) {
Biome currentBiome = entity.getEntity().getLocation().getBlock().getBiome();
return names.contains(currentBiome.name());
}
@Override
public boolean isMet(ConditionInstance instance) {
return names.contains(instance.getLocation().getBlock().getBiome().name());
}
}

View File

@ -6,36 +6,44 @@ import java.util.stream.Stream;
import net.Indyuce.mmocore.MMOCore;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
public class ConditionInstance {
private final Entity entity;
private final Location applied;
private final List<String> regions;
private final Entity entity;
private final Location applied;
private final List<String> regions;
public ConditionInstance(Entity entity) {
this(entity, entity.getLocation());
}
public ConditionInstance(@NotNull Entity entity) {
this(entity, entity.getLocation());
}
public ConditionInstance(Entity entity, Location applied) {
this.entity = entity;
this.regions = MMOCore.plugin.regionHandler.getRegions(this.applied = applied);
regions.add("__global__");
}
public ConditionInstance(@NotNull Entity entity, @NotNull Location applied) {
this.entity = entity;
this.regions = MMOCore.plugin.regionHandler.getRegions(this.applied = applied);
public boolean isInRegion(String name) {
return regions.contains(name);
}
regions.add("__global__");
}
public Location getAppliedLocation() {
return applied;
}
public boolean isInRegion(String name) {
return regions.contains(name);
}
public Entity getEntity() {
return entity;
}
@Deprecated
public Location getAppliedLocation() {
return applied;
}
public Stream<String> getRegionStream() {
return regions.stream();
}
@NotNull
public Location getLocation() {
return applied;
}
@NotNull
public Entity getEntity() {
return entity;
}
public Stream<String> getRegionStream() {
return regions.stream();
}
}

View File

@ -6,7 +6,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
public class DistanceCondition extends Condition{
public class DistanceCondition extends Condition {
private final Location location;
private final double distance;
@ -17,18 +17,14 @@ public class DistanceCondition extends Condition{
Validate.isTrue(config.contains("y"));
Validate.isTrue(config.contains("z"));
Validate.isTrue(config.contains("distance"));
Validate.isTrue(Bukkit.getWorld(config.getString("world"))!=null,"This world doesn't exist");
location=new Location(Bukkit.getWorld(config.getString("world")),config.getDouble("x"),
config.getDouble("y"),config.getDouble("z"));
distance=config.getDouble("distance");
Validate.isTrue(Bukkit.getWorld(config.getString("world")) != null, "This world doesn't exist");
location = new Location(Bukkit.getWorld(config.getString("world")), config.getDouble("x"),
config.getDouble("y"), config.getDouble("z"));
distance = config.getDouble("distance");
}
@Override
public boolean isMet(ConditionInstance entity) {
Entity entity1=entity.getEntity();
return entity1.getWorld().equals(location.getWorld())&&location.distance(entity1.getLocation())<distance;
public boolean isMet(ConditionInstance instance) {
return instance.getLocation().getWorld().equals(location.getWorld()) && location.distance(instance.getLocation()) < distance;
}
}

View File

@ -21,17 +21,13 @@ public class TimeCondition extends Condition {
@Override
public boolean isMet(ConditionInstance entity) {
if (entity.getEntity() instanceof Player player) {
long time = player.getWorld().getTime();
long time = entity.getLocation().getWorld().getTime();
if (min < max) {
return time > min && time < max;
} else {
// Allows for wrapping times, such as min=20000 max=6000
return time > min || time < max;
}
if (min < max) {
return time > min && time < max;
} else {
// Allows for wrapping times, such as min=20000 max=6000
return time > min || time < max;
}
return false;
}
}

View File

@ -18,15 +18,13 @@ public class WeatherCondition extends Condition {
@Override
public boolean isMet(ConditionInstance entity) {
if (entity.getEntity() instanceof Player player) {
boolean isClear = player.getWorld().isClearWeather();
boolean hasStorm = player.getWorld().hasStorm();
boolean isClear = entity.getLocation().getWorld().isClearWeather();
boolean hasStorm = entity.getLocation().getWorld().hasStorm();
if (condition.equalsIgnoreCase("clear")) {
return isClear;
} else if (condition.equalsIgnoreCase("stormy")) {
return hasStorm;
}
if (condition.equalsIgnoreCase("clear")) {
return isClear;
} else if (condition.equalsIgnoreCase("stormy")) {
return hasStorm;
}
return false;

View File

@ -17,6 +17,6 @@ public class WorldCondition extends Condition {
@Override
public boolean isMet(ConditionInstance entity) {
return names.contains(entity.getEntity().getWorld().getName()) || names.contains("__global__");
return names.contains(entity.getLocation().getWorld().getName()) || names.contains("__global__");
}
}

View File

@ -5,6 +5,7 @@ import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.player.attribute.MMOCoreAttributeStatHandler;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -46,8 +47,9 @@ public class AttributeManager implements MMOCoreManager {
MMOCore.log(Level.WARNING, "Could not load attribute '" + key + "': " + exception.getMessage());
}
final ConfigurationSection statsConfig = new ConfigFile(MythicLib.plugin, "", "stats").getConfig();
for (PlayerAttribute attr : getAll()) {
final MMOCoreAttributeStatHandler handler = new MMOCoreAttributeStatHandler(attr);
final MMOCoreAttributeStatHandler handler = new MMOCoreAttributeStatHandler(statsConfig, attr);
MythicLib.plugin.getStats().registerStat(handler.getStat(), handler);
MythicLib.plugin.getStats().registerStat(handler.getStat() + "_PERCENT", handler);
}

View File

@ -9,7 +9,7 @@ import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.io.File;
@ -25,10 +25,8 @@ public class ExperienceManager implements MMOCoreManager {
* Experience sources from the exp-sources.yml config file where you can
* input any exp source which can later be used along with the 'from'
* exp source anywhere in the plugin.
* <p>
* TODO First needs to edit the exp-source current structure. This is going to break a lot of things
*
* @deprecated See TODO
* @deprecated TODO First needs to edit the exp-source current structure. This is going to break a lot of things
*/
@Deprecated
private final Map<String, List<ExperienceSource<?>>> publicExpSources = new HashMap<>();
@ -55,6 +53,7 @@ public class ExperienceManager implements MMOCoreManager {
return expCurves.containsKey(id);
}
@NotNull
public ExpCurve getCurveOrThrow(String id) {
Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'");
return expCurves.get(id);
@ -70,10 +69,12 @@ public class ExperienceManager implements MMOCoreManager {
return expTables.containsKey(id);
}
@NotNull
public ExperienceTable getTableOrThrow(String id) {
return Objects.requireNonNull(expTables.get(id), "Could not find exp table with ID '" + id + "'");
}
@NotNull
public ExperienceTable loadExperienceTable(Object obj) {
if (obj instanceof ConfigurationSection)
@ -99,7 +100,7 @@ public class ExperienceManager implements MMOCoreManager {
expCurves.clear();
expTables.clear();
managers.values().forEach(HandlerList::unregisterAll);
managers.forEach((c, manager) -> manager.close());
managers.clear();
}

View File

@ -115,8 +115,9 @@ public class RestrictionManager implements MMOCoreManager {
String parentFormat = formatId(config.getString("parent"));
parent = Objects.requireNonNull(map.get(parentFormat), "Could not find parent with ID '" + parentFormat + "'");
}
for (String key : config.getStringList("can-mine"))
mineable.add(MMOCore.plugin.loadManager.loadBlockType(new MMOLineConfig(key)).generateKey());
if (config.contains("can-mine"))
for (String key : config.getStringList("can-mine"))
mineable.add(MMOCore.plugin.loadManager.loadBlockType(new MMOLineConfig(key)).generateKey());
}
/**

View File

@ -78,15 +78,12 @@ public class MMOCoreDataSynchronizer extends SQLDataSynchronizer<PlayerData> {
getData().setUnlockedItems(unlockedItems);
if (!isEmpty(result.getString("guild"))) {
final Guild guild = MMOCore.plugin.dataProvider.getGuildManager().getGuild(result.getString("guild"));
if (guild != null)
getData().setGuild(guild.hasMember(getData().getUniqueId()) ? guild : null);
if (guild != null) getData().setGuild(guild.hasMember(getData().getUniqueId()) ? guild : null);
}
if (!isEmpty(result.getString("attributes")))
getData().getAttributes().load(result.getString("attributes"));
if (!isEmpty(result.getString("attributes"))) getData().getAttributes().load(result.getString("attributes"));
if (!isEmpty(result.getString("professions")))
getData().getCollectionSkills().load(result.getString("professions"));
if (!isEmpty(result.getString("quests")))
getData().getQuestData().load(result.getString("quests"));
if (!isEmpty(result.getString("quests"))) getData().getQuestData().load(result.getString("quests"));
getData().getQuestData().updateBossBar();
if (!isEmpty(result.getString("waypoints")))
getData().getWaypoints().addAll(MMOCoreUtils.jsonArrayToList(result.getString("waypoints")));
@ -101,8 +98,7 @@ public class MMOCoreDataSynchronizer extends SQLDataSynchronizer<PlayerData> {
JsonObject object = MythicLib.plugin.getGson().fromJson(result.getString("bound_skills"), JsonObject.class);
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
ClassSkill skill = getData().getProfess().getSkill(entry.getValue().getAsString());
if (skill != null)
getData().bindSkill(Integer.parseInt(entry.getKey()), skill);
if (skill != null) getData().bindSkill(Integer.parseInt(entry.getKey()), skill);
}
}
@ -123,15 +119,17 @@ public class MMOCoreDataSynchronizer extends SQLDataSynchronizer<PlayerData> {
* These should be loaded after to make sure that the
* MAX_MANA, MAX_STAMINA & MAX_STELLIUM stats are already loaded.
*/
double health = result.getDouble("health");
getData().setMana(result.getDouble("mana"));
getData().setStamina(result.getDouble("stamina"));
getData().setStellium(result.getDouble("stellium"));
if (getData().isOnline()) {
//If the player is not dead and the health is 0, this means that the data was
//missing from the data base and it gives full health to the player.
health = health == 0 && !getData().getPlayer().isDead() ? getData().getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue() : health;
health = Math.max(Math.min(health, getData().getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()), 0);
if (getData().isOnline() && !getData().getPlayer().isDead()) {
/*
* If the player is not dead and the health is 0, this means that the data was
* missing from the data base and it gives full health to the player. If the
* player is dead however, it must not account for that subtle edge case.
*/
final double health = MMOCoreUtils.fixResource(result.getDouble("health"), getData().getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
getData().getPlayer().setHealth(health);
}

View File

@ -134,7 +134,7 @@ public class YAMLPlayerDataHandler extends YAMLSynchronizedDataHandler<PlayerDat
data.setStamina(config.contains("stamina") ? config.getDouble("stamina") : data.getStats().getStat("MAX_STAMINA"));
data.setStellium(config.contains("stellium") ? config.getDouble("stellium") : data.getStats().getStat("MAX_STELLIUM"));
if (data.isOnline())
if (data.isOnline() && !data.getPlayer().isDead())
data.getPlayer().setHealth(MMOCoreUtils.fixResource(config.getDouble("health"), data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
}

View File

@ -1,19 +1,23 @@
package net.Indyuce.mmocore.manager.profession;
import io.lumine.mythic.lib.util.Closeable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import java.util.HashSet;
import java.util.Set;
public abstract class ExperienceSourceManager<T extends ExperienceSource> implements Listener {
public abstract class ExperienceSourceManager<T extends ExperienceSource> implements Listener, Closeable {
/**
* List of all active experience sources
*/
private final Set<T> sources = new HashSet<>();
private boolean open = true;
public ExperienceSourceManager() {
Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
@ -23,6 +27,19 @@ public abstract class ExperienceSourceManager<T extends ExperienceSource> implem
sources.add(source);
}
public void whenClosed() {
// Nothing by default
}
@Override
public void close() {
Validate.isTrue(open, "Manager is already closed");
open = false;
HandlerList.unregisterAll(this);
whenClosed();
}
public Set<T> getSources() {
return sources;
}

View File

@ -10,6 +10,9 @@ import net.Indyuce.mmocore.loot.fishing.FishingDropItem;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.logging.Level;
@ -36,8 +39,9 @@ public class FishingManager extends SpecificProfessionManager {
MMOCore.plugin.statManager.registerProfession("CRITICAL_FISHING_FAILURE_CHANCE", getLinkedProfession());
}
public FishingDropTable calculateDropTable(Entity entity) {
ConditionInstance conditionEntity = new ConditionInstance(entity);
@NotNull
public FishingDropTable calculateDropTable(@NotNull Player player, @NotNull FishHook hook) {
ConditionInstance conditionEntity = new ConditionInstance(player, hook.getLocation());
for (FishingDropTable table : tables)
if (table.areConditionsMet(conditionEntity))

View File

@ -16,7 +16,6 @@ import org.bukkit.GameMode;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
@ -74,6 +73,9 @@ public class KeyCombos implements SkillCastingListener {
if (player.getGameMode() == GameMode.CREATIVE && !MMOCore.plugin.configManager.canCreativeCast)
return;
// Don't start combos if no skills are bound
if (playerData.getBoundSkills().isEmpty()) return;
// Start combo when there is an initializer key
if (!event.getData().isCasting() && initializerKey != null) {
if (event.getPressed() == initializerKey) {
@ -82,7 +84,7 @@ public class KeyCombos implements SkillCastingListener {
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
// Start combo
if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData)) && beginComboSound != null)
if (playerData.setSkillCasting() && beginComboSound != null)
beginComboSound.playTo(player);
}
@ -97,10 +99,9 @@ public class KeyCombos implements SkillCastingListener {
// 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 CustomSkillCastingInstance(playerData);
if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData)) && beginComboSound != null)
beginComboSound.playTo(player);
if (comboMap.isComboStart(event.getPressed()) && playerData.setSkillCasting()) {
casting = (CustomSkillCastingInstance) playerData.getSkillCasting();
if (beginComboSound != null) beginComboSound.playTo(player);
}
}
@ -174,7 +175,8 @@ public class KeyCombos implements SkillCastingListener {
@Override
public void onTick() {
if (actionBarOptions != null) if (actionBarOptions.isSubtitle)
if (getCaster().getBoundSkills().isEmpty()) close();
else if (actionBarOptions != null) if (actionBarOptions.isSubtitle)
getCaster().getPlayer().sendTitle(" ", actionBarOptions.format(this), 0, 20, 0);
else getCaster().displayActionBar(actionBarOptions.format(this));
}

View File

@ -55,11 +55,9 @@ public class SkillBar implements SkillCastingListener {
// 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()) {
if (playerData.setSkillCasting(new CustomSkillCastingInstance(playerData))) {
if (player.getGameMode() != GameMode.SPECTATOR && (MMOCore.plugin.configManager.canCreativeCast || player.getGameMode() != GameMode.CREATIVE) && !playerData.isCasting() && !playerData.getBoundSkills().isEmpty())
if (playerData.setSkillCasting())
MMOCore.plugin.soundManager.getSound(SoundEvent.SPELL_CAST_BEGIN).playTo(player);
}
}
}
public class CustomSkillCastingInstance extends SkillCastingInstance {

View File

@ -60,6 +60,7 @@ public class SkillScroller implements SkillCastingListener {
Player player = playerData.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE && !MMOCore.plugin.configManager.canCreativeCast)
return;
if (event.getPressed() == enterKey) {
// Leave casting mode
@ -80,7 +81,7 @@ public class SkillScroller implements SkillCastingListener {
if (event.getPressed().shouldCancelEvent()) event.setCancelled(true);
// Enter casting mode
if (!playerData.setSkillCasting(new CustomSkillCastingInstance(playerData))) {
if (!playerData.setSkillCasting()) {
return;
}

View File

@ -53,7 +53,7 @@ public class Ambers extends SkillHandler<SimpleSkillResult> implements Listener
if (passive == null)
return;
passive.getTriggeredSkill().cast(new TriggerMetadata(event.getAttacker(), event.getAttack(), event.getEntity()));
passive.getTriggeredSkill().cast(new TriggerMetadata(event));
}
public static class Amber extends BukkitRunnable {

View File

@ -45,6 +45,6 @@ public class Sneaky_Picky extends SkillHandler<SimpleSkillResult> implements Lis
if (skill == null)
return;
skill.getTriggeredSkill().cast(new TriggerMetadata(event.getAttacker(), event.getAttack(), event.getEntity()));
skill.getTriggeredSkill().cast(new TriggerMetadata(event));
}
}

View File

@ -45,7 +45,7 @@ public class FishingListener implements Listener {
* Checks for drop tables. If no drop table, just plain vanilla
* fishing OTHERWISE initialize fishing, register other listener.
*/
FishingDropTable table = MMOCore.plugin.fishingManager.calculateDropTable(player);
FishingDropTable table = MMOCore.plugin.fishingManager.calculateDropTable(player, hook);
if (table == null)
return;

View File

@ -24,6 +24,9 @@ permissions:
mmocore.currency:
description: Access to /deposit and /withdraw
default: op
mmocore.bypass-waypoint-wait:
description: Bypass waypoint waiting time
default: op
mmocore.class-select:
description: Access to /class
default: op