Compare commits

..

3 Commits

Author SHA1 Message Date
Ka0rX
ba1251bbe2 Final Bug Fixes 2023-09-12 18:32:17 +01:00
Ka0rX
4db1a93436 Bug Fixing for the refacto 2023-09-12 16:12:46 +01:00
Ka0rX
ed17756842 Huge refactor to centralize GUI API into MythicLib 2023-09-12 15:41:11 +01:00
269 changed files with 4294 additions and 6324 deletions

15
.m2/settings.xml Normal file
View File

@ -0,0 +1,15 @@
<settings>
<servers>
<server>
<id>nexus</id>
<username>${env.M2_REPO_USER}</username>
<password>${env.M2_REPO_PASS}</password>
<blocked>false</blocked>
</server>
<server>
<id>lumine</id>
<username>${env.M2_REPO_USER}</username>
<password>${env.M2_REPO_PASS}</password>
</server>
</servers>
</settings>

View File

@ -85,13 +85,13 @@
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
<id>sk89q-repo</id>
<url>https://maven.enginehub.org/repo/</url>
</repository>
<repository>
<id>sk89q-repo</id>
<url>https://maven.enginehub.org/repo/</url>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
<repository>
@ -104,39 +104,16 @@
<id>simonsators Repo</id>
<url>https://simonsator.de/repo</url>
</repository>
<!-- Heroes Repository
<repository>
<id>herocraft</id>
<url>https://nexus.hc.to/content/repositories/pub_releases</url>
</repository> -->
</repositories>
<dependencies>
<!-- Paper API -->
<!-- Spigot API -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-1.17.1</artifactId>
<version>dev</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Extra libs -->
@ -152,24 +129,14 @@
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Plugin dependencies -->
<dependency>
<groupId>io.lumine</groupId>
<artifactId>Mythic-Dist</artifactId>
<version>5.7.1</version>
<version>5.0.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.playavalon</groupId>
<artifactId>MythicDungeons</artifactId>
<version>1.4.1-SNAPSHOT-CUSTOM</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -185,7 +152,6 @@
<artifactId>placeholderapi</artifactId>
<version>2.9.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -193,7 +159,6 @@
<artifactId>VaultAPI</artifactId>
<version>1.7.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -201,18 +166,6 @@
<artifactId>worldguard-bukkit</artifactId>
<version>7.0.2-SNAPSHOT</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
@ -220,7 +173,6 @@
<artifactId>ProtocolLib</artifactId>
<version>4.8.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -228,7 +180,6 @@
<artifactId>Citizens</artifactId>
<version>2.0.30</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Party plugins -->
@ -237,7 +188,6 @@
<artifactId>DevelopmentPAFSpigot</artifactId>
<version>1.0.65</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -245,7 +195,6 @@
<artifactId>Party-and-Friends-MySQL-Edition-Spigot-API</artifactId>
<version>1.5.4-RELEASE</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -253,7 +202,6 @@
<artifactId>spigot-party-api-for-party-and-friends</artifactId>
<version>1.0.4-RELEASE</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -261,7 +209,13 @@
<artifactId>OBTeam</artifactId>
<version>1.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.playavalon</groupId>
<artifactId>DungeonParties</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -269,7 +223,6 @@
<artifactId>Parties</artifactId>
<version>3.1.14</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -277,7 +230,6 @@
<artifactId>mcMMO</artifactId>
<version>2.1.209</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -285,15 +237,6 @@
<artifactId>DungeonsXL</artifactId>
<version>0.18-SNAPSHOT-1149</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.herocraftonline</groupId>
<artifactId>Heroes</artifactId>
<version>1.9.22</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -301,7 +244,6 @@
<artifactId>Bedrock</artifactId>
<version>1.2.5</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -309,7 +251,6 @@
<artifactId>Dungeons</artifactId>
<version>1.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Quest Plugins -->
@ -318,28 +259,24 @@
<artifactId>Quests</artifactId>
<version>4.4.1-b340</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>fr.skytasul.quests</groupId>
<artifactId>BeautyQuests</artifactId>
<version>0.19.5</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.guillaumevdn</groupId>
<artifactId>QuestCreator</artifactId>
<version>6.39.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.guillaumevdn</groupId>
<artifactId>GCore</artifactId>
<version>8.39.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Guild plugins -->
@ -352,11 +289,10 @@
</dependency>
<dependency>
<groupId>com.github.UlrichBR</groupId>
<artifactId>UClansV7-API</artifactId>
<version>7.1.0</version>
<groupId>me.ulrich</groupId>
<artifactId>UltimateClans</artifactId>
<version>6.0.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -364,7 +300,6 @@
<artifactId>Guilds</artifactId>
<version>3.5.6.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
@ -372,7 +307,6 @@
<artifactId>Kingdoms</artifactId>
<version>1.15.5</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>

View File

@ -4,7 +4,6 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.data.sql.SQLDataSource;
import io.lumine.mythic.lib.metrics.bukkit.Metrics;
import io.lumine.mythic.lib.util.MMOPlugin;
import io.lumine.mythic.lib.version.SpigotPlugin;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.AttributeModifier;
@ -50,18 +49,18 @@ import net.Indyuce.mmocore.script.mechanic.ManaMechanic;
import net.Indyuce.mmocore.script.mechanic.StaminaMechanic;
import net.Indyuce.mmocore.script.mechanic.StelliumMechanic;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import net.Indyuce.mmocore.skill.trigger.MMOCoreTriggerType;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.event.EventPriority;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.logging.Level;
public class MMOCore extends MMOPlugin {
public class MMOCore extends JavaPlugin {
public static MMOCore plugin;
public final WaypointManager waypointManager = new WaypointManager();
public final SoundManager soundManager = new SoundManager();
@ -117,7 +116,6 @@ public class MMOCore extends MMOPlugin {
MythicLib.plugin.getEntities().registerRelationHandler(new PartyRelationHandler());
MythicLib.plugin.getEntities().registerRelationHandler(new GuildRelationHandler());
MythicLib.plugin.getModifiers().registerModifierType("attribute", configObject -> new AttributeModifier(configObject));
MMOCoreTriggerType.registerAll();
// Custom scripts
MythicLib.plugin.getSkills().registerMechanic("mana", config -> new ManaMechanic(config));
@ -157,7 +155,7 @@ public class MMOCore extends MMOPlugin {
}
if (getConfig().isConfigurationSection("default-playerdata"))
playerDataManager.loadDefaultData(getConfig().getConfigurationSection("default-playerdata"));
dataProvider.getDataManager().loadDefaultData(getConfig().getConfigurationSection("default-playerdata"));
if (Bukkit.getPluginManager().getPlugin("Vault") != null) economy = new VaultEconomy();
@ -207,6 +205,8 @@ public class MMOCore extends MMOPlugin {
if (Bukkit.getPluginManager().getPlugin("MMOMana") != null) {
getLogger().log(Level.SEVERE, ChatColor.DARK_RED + "MMOCore is not meant to be used with MMOItems ManaAndStamina");
getLogger().log(Level.SEVERE, ChatColor.DARK_RED + "Please read the installation guide!");
Bukkit.broadcastMessage(ChatColor.DARK_RED + "[MMOCore] MMOCore is not meant to be used with MMOItems ManaAndStamina");
Bukkit.broadcastMessage(ChatColor.DARK_RED + "[MMOCore] Please read the installation guide!");
return;
}
@ -216,10 +216,10 @@ public class MMOCore extends MMOPlugin {
try {
String partyPluginName = UtilityMethods.enumName(getConfig().getString("party-plugin"));
PartyModuleType moduleType = PartyModuleType.valueOf(partyPluginName);
Validate.isTrue(moduleType.isValid(), "Plugin " + moduleType.getPluginName() + " is not installed");
Validate.isTrue(moduleType.isValid(), "Plugin '" + moduleType.name() + "' is not installed");
partyModule = moduleType.provideModule();
getLogger().log(Level.INFO, "Hooked parties onto " + moduleType.getPluginName());
} catch (Throwable exception) {
getLogger().log(Level.WARNING, "Hooked parties onto " + moduleType.getPluginName());
} catch (RuntimeException exception) {
getLogger().log(Level.WARNING, "Could not initialize party module: " + exception.getMessage());
partyModule = new MMOCorePartyModule();
}
@ -230,7 +230,7 @@ public class MMOCore extends MMOPlugin {
GuildModuleType moduleType = GuildModuleType.valueOf(pluginName);
Validate.isTrue(moduleType.isValid(), "Plugin '" + moduleType.name() + "' is not installed");
guildModule = moduleType.provideModule();
getLogger().log(Level.INFO, "Hooked guilds onto " + moduleType.getPluginName());
getLogger().log(Level.WARNING, "Hooked guilds onto " + moduleType.getPluginName());
} catch (RuntimeException exception) {
getLogger().log(Level.WARNING, "Could not initialize guild module: " + exception.getMessage());
guildModule = new MMOCoreGuildModule();
@ -238,8 +238,9 @@ public class MMOCore extends MMOPlugin {
// Skill casting
try {
final SkillCastingMode mode = SkillCastingMode.valueOf(UtilityMethods.enumName(getConfig().getString("skill-casting.mode")));
SkillCastingMode mode = SkillCastingMode.valueOf(UtilityMethods.enumName(getConfig().getString("skill-casting.mode")));
mode.setCurrent(getConfig().getConfigurationSection("skill-casting"));
} catch (RuntimeException exception) {
getLogger().log(Level.WARNING, "Could not load skill casting: " + exception.getMessage());
}
@ -260,7 +261,7 @@ public class MMOCore extends MMOPlugin {
playerDataManager.initialize(EventPriority.LOW, EventPriority.NORMAL);
// load guild data after loading player data
nativeGuildManager.load();
dataProvider.getGuildManager().load();
// Toggleable Commands
ToggleableCommand.register();
@ -275,11 +276,12 @@ public class MMOCore extends MMOPlugin {
public void onDisable() {
// Save guild info
for (Guild guild : nativeGuildManager.getAll())
nativeGuildManager.save(guild);
for (Guild guild : dataProvider.getGuildManager().getAll())
dataProvider.getGuildManager().save(guild);
// Close player data manager
playerDataManager.close();
// Close MySQL data provider (memory leaks)
playerDataManager.saveAll(false);
playerDataManager.getDataHandler().close();
// Reset active blocks
mineManager.resetRemainingBlocks();
@ -303,6 +305,8 @@ public class MMOCore extends MMOPlugin {
configManager = new ConfigManager();
if (clearBefore)
MythicLib.plugin.getSkills().initialize(true);
skillManager.initialize(clearBefore);
mineManager.initialize(clearBefore);
partyManager.initialize(clearBefore);

View File

@ -2,143 +2,47 @@ package net.Indyuce.mmocore.api;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.apache.commons.lang.Validate;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ConfigMessage {
private final String key;
private final List<String> lines = new ArrayList<>();
private final boolean papiPlaceholders, actionbar, raw;
private final List<String> messages;
private ConfigMessage(@NotNull String key) {
this.key = key;
// Initialize message list
final Object obj = MMOCore.plugin.configManager.getMessageObject(key);
if (obj == null) lines.add("<message_not_found:'" + key + "'>");
else if (obj instanceof List<?>) lines.addAll((List<String>) obj);
else {
final String tostr = obj.toString();
if (!tostr.isEmpty()) lines.add(tostr);
public ConfigMessage(String key) {
messages = MMOCore.plugin.configManager.getMessage(key);
}
// Does message include placeholders
boolean hasPlaceholders = false;
for (String str : lines)
if (str.contains("%")) {
hasPlaceholders = true;
break;
}
this.papiPlaceholders = hasPlaceholders;
// Is message for action bar
actionbar = !lines.isEmpty() && lines.get(0).startsWith("%");
if (actionbar) lines.set(0, lines.get(0).substring(1));
// Are messages raw (JSON format)
raw = !lines.isEmpty() && (lines.get(0).startsWith("{") || lines.get(0).startsWith("["));
}
/**
* Useful for things like indicators or specific lore lines
* which are string tags not requiring more than one string
* object. An empty return value is accepted as some features
* do require the ability to fully remove text.
*
* @return First line of message, if it exists.
*/
@NotNull
public String asLine() {
return lines.isEmpty() ? "" : lines.get(0);
}
@NotNull
public List<String> getLines() {
return lines;
}
@NotNull
public ConfigMessage addPlaceholders(@NotNull Object... placeholders) {
for (int n = 0; n < lines.size(); n++) {
String line = lines.get(n);
// Apply placeholders to string
public ConfigMessage addPlaceholders(String... placeholders) {
for (int n = 0; n < messages.size(); n++) {
String line = messages.get(n);
for (int j = 0; j < placeholders.length - 1; j += 2) {
final String placeholder = String.valueOf(placeholders[j]);
line = line.replace("{" + placeholder + "}", String.valueOf(placeholders[j + 1]));
String placeholder = placeholders[j];
if (line.contains("{" + placeholder + "}"))
line = line.replace("{" + placeholder + "}", placeholders[j + 1]);
}
lines.set(n, line);
messages.set(n, line);
}
return this;
}
@Deprecated
public void sendAsJSon(Player player) {
send(player);
}
public void send(Player player) {
for (String line : lines) send(player, line);
public void send(CommandSender sender) {
messages.forEach(line -> sender.sendMessage(format(sender, line)));
}
public void send(Collection<? extends Player> players) {
for (Player player : players) for (String line : lines) send(player, line);
players.forEach(player -> messages.forEach(line -> player.sendMessage(format(player, line))));
}
/**
* Sends a line of text to a target player
*
* @param player Player to send message to. His player
* data is not necessarily fully loaded
* @param messageFormat Raw/normal message to send
*/
private void send(@NotNull Player player, String messageFormat) {
Validate.notNull(player, "Player cannot be null");
final String rawMessage = format(player, messageFormat);
final PlayerData playerData = PlayerData.has(player) ? PlayerData.get(player) : null;
// Handle special case with player data + action bar
if (playerData != null && playerData.isOnline() && actionbar) {
playerData.displayActionBar(rawMessage, raw);
return;
public void sendAsJSon(Player player) {
messages.forEach(line -> MythicLib.plugin.getVersion().getWrapper().sendJson(player, format(player, line)));
}
// Normal sender
if (this.raw) {
if (actionbar) MythicLib.plugin.getVersion().getWrapper().sendActionBarRaw(player, rawMessage);
else MythicLib.plugin.getVersion().getWrapper().sendJson(player, rawMessage);
} else {
if (actionbar)
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(rawMessage));
else player.sendMessage(rawMessage);
}
}
@NotNull
private String format(@Nullable Player player, String input) {
input = MythicLib.plugin.parseColors(input);
if (!papiPlaceholders || player == null) return input; // Optimization
return MMOCore.plugin.placeholderParser.parse(player, input);
}
@NotNull
public static ConfigMessage fromKey(@NotNull String key, Object... placeholders) {
Validate.notNull(MMOCore.plugin.configManager, "MMOCore has not finished enabling");
final ConfigMessage message = new ConfigMessage(key);
if (placeholders.length != 0) message.addPlaceholders(placeholders);
return message;
private String format(CommandSender sender, String input) {
String str = MythicLib.plugin.parseColors(input);
return sender instanceof Player ? MMOCore.plugin.placeholderParser.parse((OfflinePlayer) sender, str) : str;
}
}

View File

@ -12,8 +12,8 @@ public enum SoundEvent {
SELECT_CLASS,
LEVEL_ATTRIBUTE,
RESET_ATTRIBUTES,
RESET_SKILLS,
NOT_ENOUGH_POINTS,
RESET_SKILLS
,NOT_ENOUGH_POINTS,
CANCEL_QUEST,
START_QUEST,
CLOSE_LOOT_CHEST,

View File

@ -24,7 +24,6 @@ public class SoundObject {
private final float volume;
private final float pitch;
@Deprecated
public SoundObject(String input) {
String[] split = input.split(",");
@ -44,7 +43,6 @@ public class SoundObject {
pitch = split.length > 2 ? Float.parseFloat(split[2]) : 1;
}
@Deprecated
public SoundObject(ConfigurationSection config) {
String input = config.getString("sound");
@ -67,39 +65,32 @@ public class SoundObject {
* @return If this object is custom a custom sound, potentially
* from a resource pack
*/
@Deprecated
public boolean isCustom() {
return sound == null;
}
@Nullable
@Deprecated
public Sound getSound() {
return sound;
}
@Nullable
@Deprecated
public String getKey() {
return key;
}
@Deprecated
public float getVolume() {
return volume;
}
@Deprecated
public float getPitch() {
return pitch;
}
@Deprecated
public void playTo(Player player) {
playTo(player, volume, pitch);
}
@Deprecated
public void playTo(Player player, float volume, float pitch) {
if (isCustom())
player.playSound(player.getLocation(), key, volume, pitch);
@ -107,12 +98,10 @@ public class SoundObject {
player.playSound(player.getLocation(), sound, volume, pitch);
}
@Deprecated
public void playAt(Location loc) {
playAt(loc, volume, pitch);
}
@Deprecated
public void playAt(Location loc, float volume, float pitch) {
if (isCustom())
loc.getWorld().playSound(loc, key, volume, pitch);

View File

@ -43,7 +43,7 @@ public class BlockInfo {
options.put(option, config.getBoolean("options." + key));
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING,
"Could not load option '" + key + "' from block info '" + block.display() + "': " + exception.getMessage());
"Could not load option '" + key + "' from block info '" + block.generateKey() + "': " + exception.getMessage());
}
if (config.contains("triggers")) {
@ -55,7 +55,7 @@ public class BlockInfo {
triggers.add(MMOCore.plugin.loadManager.loadTrigger(new MMOLineConfig(key)));
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING,
"Could not load trigger '" + key + "' from block info '" + block.display() + "': " + exception.getMessage());
"Could not load trigger '" + key + "' from block info '" + block.generateKey() + "': " + exception.getMessage());
}
}
@ -65,13 +65,13 @@ public class BlockInfo {
if (condition instanceof BlockCondition)
conditions.add((BlockCondition) condition);
}
}
public boolean getOption(BlockInfoOption option) {
return options.getOrDefault(option, option.getDefault());
}
@NotNull
public BlockType getBlock() {
return block;
}
@ -85,7 +85,6 @@ public class BlockInfo {
return table != null;
}
@Deprecated
public List<ItemStack> collectDrops(LootBuilder builder) {
return table != null ? table.collect(builder) : new ArrayList<>();
}

View File

@ -1,31 +1,29 @@
package net.Indyuce.mmocore.api.block;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface BlockType {
/**
* Called when placing temporary blocks
*/
void place(@NotNull BlockInfo.RegeneratingBlock placed);
void place(BlockInfo.RegeneratingBlock placed);
/**
* Called when regenerating an older block with block regen
*/
void regenerate(@NotNull BlockInfo.RegeneratingBlock regenerating);
void regenerate(BlockInfo.RegeneratingBlock regenerating);
@NotNull String display();
/**
* Generates a key used to store the BlockInfo instance in the manager map,
* the key depends on the block type to make sure there is no interference
*/
String generateKey();
/**
* Applies some extra break restrictions; returns TRUE if the block can be
* broken. This method is used to prevent non mature crops from being broken
* for example
*/
boolean breakRestrictions(@NotNull Block block);
int hashCode();
boolean equals(@Nullable Object obj);
boolean breakRestrictions(Block block);
}

View File

@ -1,14 +1,13 @@
package net.Indyuce.mmocore.api.block;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.block.BlockInfo.RegeneratingBlock;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import java.util.Objects;
import net.Indyuce.mmocore.api.block.BlockInfo.RegeneratingBlock;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.version.VersionMaterial;
public class SkullBlockType implements BlockType {
private final String value;
@ -30,7 +29,7 @@ public class SkullBlockType implements BlockType {
@Override
public void place(RegeneratingBlock block) {
Location loc = block.getLocation();
loc.getBlock().setType(Material.PLAYER_HEAD);
loc.getBlock().setType(VersionMaterial.PLAYER_HEAD.toMaterial());
// save skull orientation if replaced block is a player head
if (MMOCoreUtils.isPlayerHead(block.getBlockData().getMaterial()))
@ -49,25 +48,12 @@ public class SkullBlockType implements BlockType {
}
@Override
public String display() {
return "Skull{" + value + "}";
public String generateKey() {
return "vanilla-skull-" + value;
}
@Override
public boolean breakRestrictions(Block block) {
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SkullBlockType that = (SkullBlockType) o;
return Objects.equals(value, that.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}

View File

@ -1,7 +1,5 @@
package net.Indyuce.mmocore.api.block;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.block.BlockInfo.RegeneratingBlock;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
@ -9,7 +7,8 @@ import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData;
import java.util.Objects;
import net.Indyuce.mmocore.api.block.BlockInfo.RegeneratingBlock;
import io.lumine.mythic.lib.api.MMOLineConfig;
public class VanillaBlockType implements BlockType {
private final Material type;
@ -59,25 +58,12 @@ public class VanillaBlockType implements BlockType {
}
@Override
public String display() {
return "Vanilla{" + type.name() + "}";
public String generateKey() {
return "vanilla-block-" + type.name();
}
@Override
public boolean breakRestrictions(Block block) {
return age == 0 || (block.getBlockData() instanceof Ageable && ((Ageable) block.getBlockData()).getAge() >= age);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VanillaBlockType that = (VanillaBlockType) o;
return type == that.type;
}
@Override
public int hashCode() {
return Objects.hash(type);
}
}

View File

@ -5,7 +5,6 @@ import java.util.Set;
import java.util.UUID;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.util.item.CurrencyItemBuilder;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
@ -39,7 +38,7 @@ public class Withdraw implements Listener {
return;
withdrawing.add(player.getUniqueId());
ConfigMessage.fromKey("withdrawing").send(player);
MMOCore.plugin.configManager.getSimpleMessage("withdrawing").send(player);
Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, 20 * 20);
}
@ -61,7 +60,7 @@ public class Withdraw implements Listener {
if (!event.getPlayer().equals(player))
return;
ConfigMessage.fromKey("withdraw-cancel").send(player);
MMOCore.plugin.configManager.getSimpleMessage("withdraw-cancel").send(player);
close();
}
@ -76,13 +75,13 @@ public class Withdraw implements Listener {
try {
worth = Integer.parseInt(event.getMessage());
} catch (Exception e) {
ConfigMessage.fromKey("wrong-number").addPlaceholders("arg", event.getMessage()).send(player);
MMOCore.plugin.configManager.getSimpleMessage("wrong-number", "arg", event.getMessage()).send(player);
return;
}
int left = (int) (MMOCore.plugin.economy.getEconomy().getBalance(player) - worth);
if (left < 0) {
ConfigMessage.fromKey("not-enough-money").addPlaceholders("left", -left).send(player);
MMOCore.plugin.configManager.getSimpleMessage("not-enough-money", "left", "" + -left).send(player);
return;
}
@ -92,7 +91,7 @@ public class Withdraw implements Listener {
MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, worth);
withdrawAlgorythm(worth);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
ConfigMessage.fromKey("withdrew").addPlaceholders("worth", worth).send(player);
MMOCore.plugin.configManager.getSimpleMessage("withdrew", "worth", "" + worth).send(player);
});
}

View File

@ -4,7 +4,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.event.HandlerList;
/**
* @deprecated Use {@link io.lumine.mythic.lib.api.event.SynchronizedDataLoadEvent} instead
* @deprecated Use {@link AsyncPlayerDataLoadEvent} instead
*/
@Deprecated
public class PlayerDataLoadEvent extends PlayerDataEvent {

View File

@ -7,19 +7,13 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class PlayerEnterCastingModeEvent extends PlayerDataEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean cancelled = false;
private static final HandlerList HANDLERS = new HandlerList();
@Deprecated
public PlayerEnterCastingModeEvent(@NotNull Player who) {
super(PlayerData.get(who));
}
public PlayerEnterCastingModeEvent(@NotNull PlayerData playerData) {
super(playerData);
}
@Override
public boolean isCancelled() {
return cancelled;
@ -37,6 +31,6 @@ public class PlayerEnterCastingModeEvent extends PlayerDataEvent implements Canc
}
public static HandlerList getHandlerList(){
return HANDLERS;
return handlerList;
}
}

View File

@ -8,18 +8,13 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class PlayerExitCastingModeEvent extends PlayerDataEvent implements Cancellable {
private static final HandlerList handlerList = new HandlerList();
private boolean cancelled = false;
private static final HandlerList HANDLERS = new HandlerList();
@Deprecated
public PlayerExitCastingModeEvent(@NotNull Player who) {
super(PlayerData.get(who));
}
public PlayerExitCastingModeEvent(@NotNull PlayerData who) {
super(who);
}
@Override
public boolean isCancelled() {
@ -34,10 +29,10 @@ public class PlayerExitCastingModeEvent extends PlayerDataEvent implements Cance
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLERS;
return handlerList;
}
public static HandlerList getHandlerList() {
return HANDLERS;
return handlerList;
}
}

View File

@ -2,10 +2,11 @@ package net.Indyuce.mmocore.api.player;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.api.stat.StatInstance;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.data.SynchronizedDataHolder;
import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import io.lumine.mythic.lib.util.Closeable;
import io.lumine.mythic.lib.version.VParticle;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent;
@ -21,13 +22,10 @@ import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.api.quest.trigger.StatTrigger;
import net.Indyuce.mmocore.api.quest.trigger.Trigger;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.experience.*;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.guild.provided.Guild;
@ -45,7 +43,6 @@ 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.NodeIncrementResult;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.SkillTreeStatus;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
@ -64,28 +61,25 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerData, Closeable, ClassDataContainer {
public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerData, Closeable, ExperienceTableClaimer, ClassDataContainer {
/**
* Can be null, the {@link #getProfess()} method will return the
* player class, or the default one if this field is null.
* <p>
* NEVER access the player class using this field, you must
* use the {@link #getProfess()} method instead
*/
@Nullable
private PlayerClass profess;
private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
private double experience;
private double mana, stamina, stellium;
/**
* Saving resources (especially health) right in player data fixes TONS of issues.
* Health is stored in playerData because when saving the playerData we can't access the player health anymore as the payer is Offline.
*/
private double health, mana, stamina, stellium;
private double health;
private Guild guild;
private SkillCastingInstance skillCasting;
private final PlayerQuests questData;
@ -93,11 +87,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
private final List<UUID> friends = new ArrayList<>();
/**
* TODO Use {@link #hasUnlocked(Unlockable)} instead
* <p>
* Merge waypoints with unlocked items, and create a method
* plugin-scope to check if some item is class-specific and
* should be reset when switching class
* @deprecated Use {@link #hasUnlocked(Unlockable)} instead
*/
@Deprecated
private final Set<String> waypoints = new HashSet<>();
@ -109,13 +99,17 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
private final Map<PlayerActivity, Long> lastActivity = new HashMap<>();
private final CombatHandler combat = new CombatHandler(this);
/**
* Cached for easier access. Amount of points spent in each skill tree.
*/
private final Map<SkillTree, Integer> pointSpent = new HashMap<>();
/**
* Cached for easier access. Current status of each skill tree node.
*/
private final Map<SkillTreeNode, SkillTreeStatus> nodeStates = new HashMap<>();
private final Map<SkillTreeNode, Integer> nodeLevels = new HashMap<>();
private final Map<String, Integer> skillTreePoints = new HashMap<>();
private final Map<SkillTree, Integer> skillTreePointsSpent = new HashMap<>();
/**
* Saves the namespacedkeys of the items that have been unlocked in the form "namespace:key".
@ -127,17 +121,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
/**
* Saves the amount of times the player has claimed some
* item in any experience table. The key used in the map
* is the identifier of the exp table item.
* exp item in exp tables, for both exp tables used
*/
private final Map<String, Integer> tableItemClaims = new HashMap<>();
// NON-FINAL player data stuff made public to facilitate field change
public boolean noCooldown;
public long lastDropEvent;
public PlayerData(MMOPlayerData mmoData) {
super(MMOCore.plugin, mmoData);
super(mmoData);
questData = new PlayerQuests(this);
playerStats = new PlayerStats(this);
@ -154,6 +146,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void reload() {
try {
profess = profess == null ? null : MMOCore.plugin.classManager.get(profess.getId());
getStats().updateStats();
} catch (NullPointerException exception) {
MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data.");
}
@ -178,42 +171,23 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
if (!nodeLevels.containsKey(node)) nodeLevels.put(node, 0);
setupSkillTree();
applyTemporaryTriggers();
getStats().updateStats();
setupRemovableTrigger();
}
@Deprecated
public void setupRemovableTrigger() {
applyTemporaryTriggers();
}
//We remove all the stats and buffs associated to triggers.
getMMOPlayerData().getStatMap().getInstances().forEach(statInstance -> statInstance.removeIf(key -> key.startsWith(Trigger.TRIGGER_PREFIX)));
getMMOPlayerData().getSkillModifierMap().getInstances().forEach(skillModifierInstance -> skillModifierInstance.removeIf(key -> key.startsWith(Trigger.TRIGGER_PREFIX)));
/**
* Some triggers are marked with the {@link Removable} interface as
* they are non-permanent triggers, and they need to be re-applied
* everytime their MMOPlayerData gets flushed from the MythicLib cache
* (everytime the player logs out).
* <p>
* This method goes through all the player's experience tables that
* they have spent points into and register all their non-permanent triggers.
*/
public void applyTemporaryTriggers() {
// Remove all stats and buffs associated to triggers
resetTriggerStats();
// Experience tables from main class
if (getProfess().hasExperienceTable())
getProfess().getExperienceTable().applyTemporaryTriggers(this, getProfess());
// Experience tables from professions
if (profess.hasExperienceTable())
profess.getExperienceTable().claimRemovableTrigger(this, profess);
for (Profession profession : MMOCore.plugin.professionManager.getAll())
if (profession.hasExperienceTable())
profession.getExperienceTable().applyTemporaryTriggers(this, profession);
// Experience tables from skill tree nodes
profession.getExperienceTable().claimRemovableTrigger(this, profession);
// Stat triggers setup
for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().applyTemporaryTriggers(this, node);
node.getExperienceTable().claimRemovableTrigger(this, node);
}
public void setupSkillTree() {
@ -223,25 +197,19 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
skillTree.setupNodeStates(this);
}
public int getPointsSpent(@NotNull SkillTree skillTree) {
return skillTreePointsSpent.getOrDefault(skillTree, 0);
}
@Deprecated
public int getPointSpent(SkillTree skillTree) {
return getPointsSpent(skillTree);
return pointSpent.getOrDefault(skillTree, 0);
}
public void setSkillTreePoints(@NotNull String treeId, int points) {
if (points <= 0) skillTreePoints.remove(treeId);
else skillTreePoints.put(treeId, points);
public void setSkillTreePoints(String treeId, int points) {
skillTreePoints.put(treeId, points);
}
public void giveSkillTreePoints(@NotNull String id, int val) {
skillTreePoints.merge(id, Math.max(0, val), (points, ignored) -> Math.max(0, points + val));
public void giveSkillTreePoints(String id, int val) {
skillTreePoints.put(id, skillTreePoints.getOrDefault(id, 0) + val);
}
public int countSkillTreePoints(@NotNull SkillTree skillTree) {
public int countSkillTreePoints(SkillTree skillTree) {
return nodeLevels.keySet().stream().filter(node -> node.getTree().equals(skillTree)).mapToInt(node -> nodeLevels.get(node) * node.getSkillTreePointsConsumed()).sum();
}
@ -249,7 +217,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* Make a copy to make sure that the object
* created is independent of the state of playerData.
*/
@NotNull
public Map<String, Integer> mapSkillTreePoints() {
return new HashMap(skillTreePoints);
}
@ -262,6 +229,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return result;
}
public void clearSkillTreePoints() {
skillTreePoints.clear();
}
public void clearNodeTimesClaimed() {
final Iterator<String> ite = tableItemClaims.keySet().iterator();
while (ite.hasNext()) if (ite.next().startsWith(SkillTreeNode.KEY_PREFIX)) ite.remove();
}
public Set<Map.Entry<String, Integer>> getNodeLevelsEntrySet() {
HashMap<String, Integer> nodeLevelsString = new HashMap<>();
for (SkillTreeNode node : nodeLevels.keySet())
@ -270,8 +246,13 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
}
public void resetTriggerStats() {
getMMOPlayerData().getStatMap().getInstances().forEach(statInstance -> statInstance.removeIf(Trigger.STAT_MODIFIER_KEY::equals));
getMMOPlayerData().getSkillModifierMap().removeModifiers(Trigger.STAT_MODIFIER_KEY);
for (StatInstance instance : getMMOPlayerData().getStatMap().getInstances()) {
Iterator<StatModifier> iter = instance.getModifiers().iterator();
while (iter.hasNext()) {
StatModifier modifier = iter.next();
if (modifier.getKey().startsWith(StatTrigger.TRIGGER_PREFIX)) iter.remove();
}
}
}
@Override
@ -281,48 +262,16 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return mapped;
}
@Deprecated
public void clearSkillTrees() {
resetSkillTrees();
}
public void resetSkillTrees() {
// Un-apply triggers
for (SkillTree tree : getProfess().getSkillTrees())
for (SkillTreeNode node : tree.getNodes())
node.resetAdvancement(this, false);
// Node levels, states and points spent
public void clearNodeLevels() {
nodeLevels.clear();
nodeStates.clear();
skillTreePointsSpent.clear();
// Skill tree points
skillTreePoints.clear();
// Clear node claim count
tableItemClaims.keySet().removeIf(s -> s.startsWith(SkillTreeNode.KEY_PREFIX));
pointSpent.clear();
}
@NotNull
public NodeIncrementResult canIncrementNodeLevel(@NotNull SkillTreeNode node) {
final SkillTreeStatus skillTreeStatus = nodeStates.get(node);
// Check node state
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE)
return NodeIncrementResult.LOCKED_NODE;
// Check permission
if (!node.hasPermissionRequirement(this)) return NodeIncrementResult.PERMISSION_DENIED;
// Max node level
if (getNodeLevel(node) >= node.getMaxLevel()) return NodeIncrementResult.MAX_LEVEL_REACHED;
final int skillTreePoints = this.skillTreePoints.getOrDefault(node.getTree().getId(), 0) + this.skillTreePoints.getOrDefault("global", 0);
if (skillTreePoints < node.getSkillTreePointsConsumed()) return NodeIncrementResult.NOT_ENOUGH_POINTS;
return NodeIncrementResult.SUCCESS;
public boolean canIncrementNodeLevel(SkillTreeNode node) {
SkillTreeStatus skillTreeStatus = nodeStates.get(node);
//Check the State of the node
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE) return false;
return node.hasPermissionRequirement(this) && getNodeLevel(node) < node.getMaxLevel() && (skillTreePoints.getOrDefault(node.getTree().getId(), 0) + skillTreePoints.getOrDefault("global", 0) >= node.getSkillTreePointsConsumed());
}
/**
@ -330,39 +279,32 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* Consumes skill tree points from the tree first and then consumes the
* global skill-tree points ('all')
*/
public void incrementNodeLevel(@NotNull SkillTreeNode node) {
final int newLevel = addNodeLevels(node, 1);
node.updateAdvancement(this, newLevel); // Claim the node exp table
public void incrementNodeLevel(SkillTreeNode node) {
setNodeLevel(node, getNodeLevel(node) + 1);
// Claims the nodes experience table.
node.getExperienceTable().claim(this, getNodeLevel(node), node);
// Update node state
nodeStates.compute(node, (key, status) -> status == SkillTreeStatus.UNLOCKABLE ? SkillTreeStatus.UNLOCKED : status);
// Consume skill tree points
final AtomicInteger cost = new AtomicInteger(node.getSkillTreePointsConsumed());
skillTreePoints.computeIfPresent(node.getTree().getId(), (key, points) -> {
final int withdrawn = Math.min(points, cost.get());
cost.set(cost.get() - withdrawn);
return points <= withdrawn ? null : points - withdrawn;
});
if (cost.get() > 0) withdrawSkillTreePoints("global", cost.get());
// Reload node states from full skill tree
for (SkillTreeNode node1 : node.getTree().getNodes()) nodeStates.remove(node1);
if (nodeStates.get(node) == SkillTreeStatus.UNLOCKABLE) setNodeState(node, SkillTreeStatus.UNLOCKED);
int pointToWithdraw = node.getSkillTreePointsConsumed();
if (skillTreePoints.get(node.getTree().getId()) > 0) {
int pointWithdrawn = Math.min(pointToWithdraw, skillTreePoints.get(node.getTree().getId()));
withdrawSkillTreePoints(node.getTree().getId(), pointWithdrawn);
pointToWithdraw -= pointWithdrawn;
}
if (pointToWithdraw > 0) withdrawSkillTreePoints("global", pointToWithdraw);
// We unload the nodeStates map (for the skill tree) and reload it completely
for (SkillTreeNode node1 : node.getTree().getNodes())
nodeStates.remove(node1);
node.getTree().setupNodeStates(this);
}
@Deprecated
public int getSkillTreePoint(String treeId) {
return getSkillTreePoints(treeId);
}
public int getSkillTreePoints(@NotNull String treeId) {
public int getSkillTreePoint(String treeId) {
return skillTreePoints.getOrDefault(treeId, 0);
}
public void withdrawSkillTreePoints(@NotNull String treeId, int withdrawn) {
final int cost = Math.max(0, withdrawn);
skillTreePoints.computeIfPresent(treeId, (ignored, points) -> cost >= points ? null : points - cost);
public void withdrawSkillTreePoints(String treeId, int withdraw) {
skillTreePoints.put(treeId, skillTreePoints.get(treeId) - withdraw);
}
public void setNodeState(SkillTreeNode node, SkillTreeStatus skillTreeStatus) {
@ -381,24 +323,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return nodeLevels.getOrDefault(node, 0);
}
public void setNodeLevel(@NotNull SkillTreeNode node, int nodeLevel) {
nodeLevels.compute(node, (ignored, currentLevelInteger) -> {
final int currentLevel = currentLevelInteger == null ? 0 : currentLevelInteger;
final int delta = (nodeLevel - currentLevel) * node.getSkillTreePointsConsumed();
skillTreePointsSpent.merge(node.getTree(), delta, (level, ignored2) -> level + delta);
return nodeLevel;
});
}
public int addNodeLevels(@NotNull SkillTreeNode node, int increment) {
final int delta = increment * node.getSkillTreePointsConsumed();
skillTreePointsSpent.merge(node.getTree(), delta, (points, ignored) -> points + delta);
return nodeLevels.merge(node, increment, (level, ignored) -> level + increment);
public void setNodeLevel(SkillTreeNode node, int nodeLevel) {
int delta = (nodeLevel - nodeLevels.getOrDefault(node, 0)) * node.getSkillTreePointsConsumed();
pointSpent.put(node.getTree(), pointSpent.getOrDefault(node.getTree(), 0) + delta);
nodeLevels.put(node, nodeLevel);
}
public void resetSkillTree(SkillTree skillTree) {
for (SkillTreeNode node : skillTree.getNodes()) {
node.resetAdvancement(this, true);
node.getExperienceTable().reset(this, node);
setNodeLevel(node, 0);
nodeStates.remove(node);
}
@ -409,6 +342,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return new HashMap<>(nodeStates);
}
public void clearNodeStates() {
nodeStates.clear();
}
@Override
public Map<String, Integer> getNodeTimesClaimed() {
Map<String, Integer> result = new HashMap<>();
@ -433,11 +370,11 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/
public boolean unlock(Unlockable unlockable) {
Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot unlock an item unlocked by default");
final boolean wasLocked = unlockedItems.add(unlockable.getUnlockNamespacedKey());
if (wasLocked) {
unlockable.whenUnlocked(this);
final boolean wasLocked = unlockedItems.add(unlockable.getUnlockNamespacedKey());
// Call the event synchronously
if (wasLocked)
Bukkit.getScheduler().runTask(MythicLib.plugin, () -> Bukkit.getPluginManager().callEvent(new ItemUnlockedEvent(this, unlockable.getUnlockNamespacedKey())));
}
return wasLocked;
}
@ -449,11 +386,11 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/
public boolean lock(Unlockable unlockable) {
Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot lock an item unlocked by default");
boolean wasUnlocked = unlockedItems.remove(unlockable.getUnlockNamespacedKey());
if (wasUnlocked) {
unlockable.whenLocked(this);
boolean wasUnlocked = unlockedItems.remove(unlockable.getUnlockNamespacedKey());
if (wasUnlocked)
//Calls the event synchronously
Bukkit.getScheduler().runTask(MythicLib.plugin, () -> Bukkit.getPluginManager().callEvent(new ItemLockedEvent(this, unlockable.getUnlockNamespacedKey())));
}
return wasUnlocked;
}
@ -466,7 +403,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
this.unlockedItems.addAll(unlockedItems);
}
@Deprecated
public void resetTimesClaimed() {
tableItemClaims.clear();
}
@ -493,7 +429,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
boundSkills.forEach((slot, info) -> info.close());
// Stop skill casting
if (isCasting()) leaveSkillCasting(true);
if (isCasting()) leaveSkillCasting();
}
public List<UUID> getFriends() {
@ -569,10 +505,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return sum;
}
@NotNull
@Deprecated
public List<ClassSkill> getUnlockedSkills() {
return getProfess().getSkills().stream()
.filter(skill -> hasUnlocked(skill) && hasUnlockedLevel(skill))
.filter((classSkill) -> hasUnlocked(classSkill))
.collect(Collectors.toList());
}
@ -591,38 +527,22 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return skillTreeReallocationPoints;
}
public int getClaims(@NotNull ExperienceObject object, @NotNull ExperienceItem item) {
final ExperienceTable table = object.getExperienceTable();
@Override
public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) {
return getClaims(object.getKey() + "." + table.getId() + "." + item.getId());
}
/**
* @param key The identifier of an exp table item.
* @return Amount of times an item has been claimed
* inside an experience table.
*/
public int getClaims(@NotNull String key) {
public int getClaims(String key) {
return tableItemClaims.getOrDefault(key, 0);
}
public void setClaims(@NotNull ExperienceObject object, @NotNull ExperienceItem item, int times) {
final ExperienceTable table = object.getExperienceTable();
setClaims(object.getKey() + "." + table.getId() + "." + item.getId(), times);
}
public void setClaims(@NotNull String itemKey, int times) {
if (times <= 0) tableItemClaims.remove(itemKey);
else tableItemClaims.put(itemKey, times);
}
@Deprecated
@Override
public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) {
setClaims(object.getKey() + "." + table.getId() + "." + item.getId(), times);
}
@Deprecated
public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) {
return getClaims(object.getKey() + "." + table.getId() + "." + item.getId());
public void setClaims(String key, int times) {
tableItemClaims.put(key, times);
}
public Map<String, Integer> getItemClaims() {
@ -646,8 +566,9 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void setLevel(int level) {
this.level = Math.max(1, level);
if (isOnline()) {
if (isSynchronized()) getStats().updateStats();
getStats().updateStats();
refreshVanillaExp();
}
}
@ -805,7 +726,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
setLastActivity(PlayerActivity.FRIEND_REQUEST);
FriendRequest request = new FriendRequest(this, target);
ConfigMessage.fromKey("friend-request").addPlaceholders("player", getPlayer().getName(), "uuid", request.getUniqueId().toString()).send(target.getPlayer());
new ConfigMessage("friend-request").addPlaceholders("player", getPlayer().getName(), "uuid", request.getUniqueId().toString()).sendAsJSon(target.getPlayer());
MMOCore.plugin.requestManager.registerRequest(request);
}
@ -835,15 +756,14 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void run() {
if (!isOnline() || getPlayer().getLocation().getBlockX() != x || getPlayer().getLocation().getBlockY() != y || getPlayer().getLocation().getBlockZ() != z) {
if (isOnline()) {
MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_CANCELLED).playTo(getPlayer());
ConfigMessage.fromKey("warping-canceled").send(getPlayer());
}
MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer());
giveStellium(cost, PlayerResourceUpdateEvent.UpdateReason.USE_WAYPOINT);
cancel();
return;
}
MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", String.valueOf((warpTime - t) / 20)).send(getPlayer());
if (hasPerm || t++ >= warpTime) {
getPlayer().teleport(target.getLocation());
getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
@ -852,11 +772,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return;
}
ConfigMessage.fromKey("warping-comencing", "left", String.valueOf((warpTime - t) / 20)).send(getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_CHARGE).playTo(getPlayer(), 1, (float) (.5 + t * 1.5 / warpTime));
final double r = Math.sin((double) t / warpTime * Math.PI);
for (double j = 0; j < Math.PI * 2; j += Math.PI / 4)
getPlayer().getLocation().getWorld().spawnParticle(VParticle.REDSTONE.get(), getPlayer().getLocation().add(Math.cos((double) 5 * t / warpTime + j) * r, (double) 2 * t / warpTime, Math.sin((double) 5 * t / warpTime + j) * r), 1, new Particle.DustOptions(Color.PURPLE, 1.25f));
getPlayer().getLocation().getWorld().spawnParticle(Particle.REDSTONE, getPlayer().getLocation().add(Math.cos((double) 5 * t / warpTime + j) * r, (double) 2 * t / warpTime, Math.sin((double) 5 * t / warpTime + j) * r), 1, new Particle.DustOptions(Color.PURPLE, 1.25f));
}
}.runTaskTimer(MMOCore.plugin, 0, 1);
}
@ -921,7 +840,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Experience hologram
if (hologramLocation != null && isOnline())
MMOCoreUtils.displayIndicator(hologramLocation, ConfigMessage.fromKey("exp-hologram", "exp", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience())).asLine());
MMOCoreUtils.displayIndicator(hologramLocation, MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience())).message());
experience = Math.max(0, experience + event.getExperience());
@ -938,15 +857,16 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
level = getLevel() + 1;
// Apply class experience table
getProfess().updateAdvancement(this, level);
if (getProfess().hasExperienceTable())
getProfess().getExperienceTable().claim(this, level, getProfess());
}
if (level > oldLevel) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(this, null, oldLevel, level));
if (isOnline()) {
ConfigMessage.fromKey("level-up").addPlaceholders("level", String.valueOf(level)).send(getPlayer());
new ConfigMessage("level-up").addPlaceholders("level", String.valueOf(level)).send(getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(getPlayer());
new SmallParticleEffect(getPlayer(), VParticle.INSTANT_EFFECT.get());
new SmallParticleEffect(getPlayer(), Particle.SPELL_INSTANT);
}
getStats().updateStats();
}
@ -1033,7 +953,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
stellium = Math.max(0, Math.min(stellium + event.getAmount(), max));
}
@Deprecated
@Override
public double getHealth() {
return isOnline() ? getPlayer().getHealth() : health;
@ -1053,10 +972,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return stellium;
}
public double getCachedHealth() {
return health;
}
public PlayerStats getStats() {
return playerStats;
}
@ -1097,16 +1012,23 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated
public boolean setSkillCasting(@NotNull SkillCastingInstance skillCasting) {
return setSkillCasting();
Validate.isTrue(!isCasting(), "Player already in casting mode");
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
skillCasting.close();
setSkillCasting();
return true;
}
/**
* @return If the PlayerEnterCastingModeEvent successfully put the player
* into casting mode, otherwise if the event is cancelled, returns false.
* @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 boolean setSkillCasting() {
Validate.isTrue(!isCasting(), "Player already in casting mode");
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(this);
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
@ -1120,23 +1042,22 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
}
/**
* @return If player successfully left skill casting i.e the Bukkit
* event has not been cancelled
* 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 leaveSkillCasting(false);
}
/**
* @param skipEvent Skip firing the exit event
* @return If player successfully left skill casting i.e the Bukkit
* event has not been cancelled
* @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(this);
PlayerExitCastingModeEvent event = new PlayerExitCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
}
@ -1147,18 +1068,9 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return true;
}
public void displayActionBar(@NotNull String message) {
displayActionBar(message, false);
}
public void displayActionBar(@NotNull String message, boolean raw) {
// TODO add an option to disable action-bar properly in all casting modes
if (ChatColor.stripColor(message).isEmpty()) return;
public void displayActionBar(String message) {
setLastActivity(PlayerActivity.ACTION_BAR_MESSAGE);
if (raw) MythicLib.plugin.getVersion().getWrapper().sendActionBarRaw(getPlayer(), message);
else getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
}
@Deprecated
@ -1168,7 +1080,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated
public void setAttribute(String id, int value) {
attributes.getInstance(id).setBase(value);
attributes.setBaseAttribute(id, value);
}
@Override
@ -1254,8 +1166,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Clear bound skills
boundSkills.forEach((slot, info) -> info.close());
boundSkills.clear();
applyTemporaryTriggers();
setupRemovableTrigger();
// Update stats
if (isOnline()) getStats().updateStats();
}
@ -1266,8 +1177,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Nullable
public ClassSkill getBoundSkill(int slot) {
final BoundSkillInfo found = boundSkills.get(slot);
return found != null ? found.getClassSkill() : null;
return boundSkills.containsKey(slot) ? boundSkills.get(slot).getClassSkill() : null;
}
@Deprecated
@ -1283,39 +1193,24 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/
public void bindSkill(int slot, @NotNull ClassSkill skill) {
Validate.notNull(skill, "Skill cannot be null");
if (slot <= 0) return;
// Friendly error in case server owner makes a skill permanent while players have already bound it
if (skill.isPermanent()) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Attempted to bind permanent skill " + skill.getSkill().getName() + " to player " + getUniqueId());
return;
}
if (slot >= 0) {
// Unbinds the previous skill (important for passive skills)
unbindSkill(slot);
final SkillSlot skillSlot = getProfess().getSkillSlot(slot);
boundSkills.put(slot, new BoundSkillInfo(skillSlot, skill, this));
}
}
@Nullable
public BoundSkillInfo unbindSkill(int slot) {
public void unbindSkill(int slot) {
final @Nullable BoundSkillInfo boundSkillInfo = boundSkills.remove(slot);
if (boundSkillInfo != null) boundSkillInfo.close();
return boundSkillInfo;
}
@NotNull
public Map<Integer, BoundSkillInfo> getBoundSkills() {
return boundSkills;
}
/**
* @return If the player has at least one active skill bound
*/
public boolean hasActiveSkillBound() {
for (BoundSkillInfo bound : boundSkills.values())
if (!bound.isPassive()) return true;
return false;
public List<ClassSkill> getBoundSkills() {
return boundSkills.values().stream().map(BoundSkillInfo::getClassSkill).collect(Collectors.toList());
}
@NotNull
@ -1372,7 +1267,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
}
public static PlayerData get(@NotNull UUID uuid) {
return MMOCore.plugin.playerDataManager.get(uuid);
return MMOCore.plugin.dataProvider.getDataManager().get(uuid);
}
/**
@ -1404,10 +1299,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* @return If player data for that player is loaded
*/
public static boolean has(UUID uuid) {
return MMOCore.plugin.playerDataManager.isLoaded(uuid);
return MMOCore.plugin.dataProvider.getDataManager().isLoaded(uuid);
}
public static Collection<PlayerData> getAll() {
return MMOCore.plugin.playerDataManager.getLoaded();
return MMOCore.plugin.dataProvider.getDataManager().getLoaded();
}
}

View File

@ -1,30 +1,36 @@
package net.Indyuce.mmocore.api.player.attribute;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.api.stat.api.InstanceModifier;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import io.lumine.mythic.lib.player.modifier.PlayerModifier;
import io.lumine.mythic.lib.util.configobject.ConfigObject;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
import java.util.UUID;
import java.text.DecimalFormat;
import java.util.Objects;
public class AttributeModifier extends InstanceModifier {
public class AttributeModifier extends PlayerModifier {
private final String attribute;
private final double value;
private final ModifierType type;
private static final DecimalFormat oneDigit = MythicLib.plugin.getMMOConfig().newDecimalFormat("0.#");
/**
* Flat attribute modifier (simplest modifier you can think about)
*/
public AttributeModifier(String key, String attribute, double value) {
super(key, value);
this.attribute = attribute;
this(key, attribute, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER);
}
/**
* Attribute modifier given by an external mechanic, like a party buff, item
* set bonuses, skills or abilities... Anything apart from items and armor.
* Attribute modifier given by an external mecanic, like a party buff, item set bonuses,
* skills or abilities... Anything apart from items and armor.
*/
public AttributeModifier(String key, String attribute, double value, ModifierType type) {
this(key, attribute, value, type, EquipmentSlot.OTHER, ModifierSource.OTHER);
@ -41,23 +47,11 @@ public class AttributeModifier extends InstanceModifier {
* @param source Type of the item granting the stat modifier
*/
public AttributeModifier(String key, String attribute, double value, ModifierType type, EquipmentSlot slot, ModifierSource source) {
this(UUID.randomUUID(), key, attribute, value, type, slot, source);
}
/**
* Attribute modifier given by an item, either a weapon or an armor piece.
*
* @param key Player modifier key
* @param attribute Attribute being modified
* @param value Value of stat modifier
* @param type Is the modifier flat or multiplicative
* @param slot Slot of the item granting the stat modifier
* @param source Type of the item granting the stat modifier
*/
public AttributeModifier(UUID uniqueId, String key, String attribute, double value, ModifierType type, EquipmentSlot slot, ModifierSource source) {
super(uniqueId, key, slot, source, value, type);
super(key, slot, source);
this.attribute = attribute;
this.value = value;
this.type = type;
}
/**
@ -68,14 +62,22 @@ public class AttributeModifier extends InstanceModifier {
* @param str The string to be parsed
*/
public AttributeModifier(String key, String attribute, String str) {
super(key, EquipmentSlot.OTHER, ModifierSource.OTHER, str);
super(key, EquipmentSlot.OTHER, ModifierSource.OTHER);
Validate.notNull(str, "String cannot be null");
Validate.notEmpty(str, "String cannot be empty");
type = str.toCharArray()[str.length() - 1] == '%' ? ModifierType.RELATIVE : ModifierType.FLAT;
value = Double.parseDouble(type == ModifierType.RELATIVE ? str.substring(0, str.length() - 1) : str);
this.attribute = attribute;
}
public AttributeModifier(ConfigObject object) {
super(object);
super(object.getString("key"), EquipmentSlot.OTHER, ModifierSource.OTHER);
String str = Objects.requireNonNull(object.getString("value"));
type = str.toCharArray()[str.length() - 1] == '%' ? ModifierType.RELATIVE : ModifierType.FLAT;
value = Double.parseDouble(type == ModifierType.RELATIVE ? str.substring(0, str.length() - 1) : str);
this.attribute = object.getString("attribute");
}
@ -83,6 +85,14 @@ public class AttributeModifier extends InstanceModifier {
return attribute;
}
public ModifierType getType() {
return type;
}
public double getValue() {
return value;
}
/**
* Used to multiply some existing stat modifier by a constant, usually an
* integer, for instance when MMOCore party modifiers scale with the
@ -91,8 +101,8 @@ public class AttributeModifier extends InstanceModifier {
* @param coef The multiplicative constant
* @return A new instance of StatModifier with modified value
*/
public AttributeModifier multiply(double coef) {
return new AttributeModifier(getUniqueId(), getKey(), attribute, value * coef, type, getSlot(), getSource());
public StatModifier multiply(double coef) {
return new StatModifier(getKey(), attribute, value * coef, type, getSlot(), getSource());
}
@Override
@ -106,4 +116,9 @@ public class AttributeModifier extends InstanceModifier {
PlayerData playerData = PlayerData.get(mmoPlayerData);
playerData.getAttributes().getInstance(attribute).removeModifier(getKey());
}
@Override
public String toString() {
return oneDigit.format(value) + (type == io.lumine.mythic.lib.player.modifier.ModifierType.RELATIVE ? "%" : "");
}
}

View File

@ -85,7 +85,7 @@ public class PlayerAttribute implements ExperienceObject {
@NotNull
@Override
public ExperienceTable getExperienceTable() {
return Objects.requireNonNull(expTable, "Attribute has no exp table");
return Objects.requireNonNull(expTable);
}
@Override

View File

@ -1,14 +1,13 @@
package net.Indyuce.mmocore.api.player.attribute;
import io.lumine.mythic.lib.MythicLib;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.stat.StatInstance;
import io.lumine.mythic.lib.gson.JsonElement;
import io.lumine.mythic.lib.gson.JsonObject;
import io.lumine.mythic.lib.player.modifier.Closeable;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import io.lumine.mythic.lib.util.Closeable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
@ -33,9 +32,11 @@ public class PlayerAttributes {
public void load(ConfigurationSection config) {
for (String key : config.getKeys(false))
try {
final String id = key.toLowerCase().replace("_", "-").replace(" ", "-");
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute called '" + id + "'");
final AttributeInstance ins = new AttributeInstance(id);
String id = key.toLowerCase().replace("_", "-").replace(" ", "-");
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute '" + id + "'");
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
AttributeInstance ins = new AttributeInstance(attribute.getId());
ins.setBase(config.getInt(key));
instances.put(id, ins);
} catch (IllegalArgumentException exception) {
@ -55,12 +56,15 @@ public class PlayerAttributes {
}
public void load(String json) {
JsonObject jo = MythicLib.plugin.getGson().fromJson(json, JsonObject.class);
Gson parser = new Gson();
JsonObject jo = parser.fromJson(json, JsonObject.class);
for (Entry<String, JsonElement> entry : jo.entrySet()) {
try {
final String id = entry.getKey().toLowerCase().replace("_", "-").replace(" ", "-");
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute called '" + id + "'");
final AttributeInstance ins = new AttributeInstance(id);
String id = entry.getKey().toLowerCase().replace("_", "-").replace(" ", "-");
Validate.isTrue(MMOCore.plugin.attributeManager.has(id), "Could not find attribute '" + id + "'");
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
AttributeInstance ins = new AttributeInstance(attribute.getId());
ins.setBase(entry.getValue().getAsInt());
instances.put(id, ins);
} catch (IllegalArgumentException exception) {
@ -109,14 +113,13 @@ public class PlayerAttributes {
return n;
}
// TODO have it extend ModifiedInstance
public class AttributeInstance {
private int spent;
private final String id, enumName;
private final Map<String, AttributeModifier> map = new HashMap<>();
public AttributeInstance(@NotNull String id) {
public AttributeInstance(String id) {
this.id = id;
this.enumName = UtilityMethods.enumName(this.id);
}
@ -138,7 +141,7 @@ public class PlayerAttributes {
}
public void addBase(int value) {
setBase(getBase() + value);
setBase(spent + value);
}
/*
@ -178,7 +181,8 @@ public class PlayerAttributes {
public AttributeModifier addModifier(AttributeModifier modifier) {
final AttributeModifier current = map.put(modifier.getKey(), modifier);
if (current instanceof Closeable) ((Closeable) current).close();
if (current != null && current instanceof Closeable)
((Closeable) current).close();
updateStats();
return current;
@ -211,12 +215,6 @@ public class PlayerAttributes {
public void updateStats() {
final PlayerAttribute attr = MMOCore.plugin.attributeManager.get(id);
final int total = getTotal();
// Remove ALL stat modifiers
for (StatInstance ins : data.getMMOPlayerData().getStatMap().getInstances())
ins.removeIf(str -> str.equals("attribute." + id));
// Register new stat modifiers
attr.getBuffs().forEach(buff -> buff.multiply(total).register(data.getMMOPlayerData()));
}
@ -225,9 +223,10 @@ public class PlayerAttributes {
}
}
@Deprecated
public void setBaseAttribute(String id, int value) {
AttributeInstance ins = instances.get(id);
if (ins != null) ins.setBase(value);
getInstances().forEach(ins -> {
if (ins.getId().equals(id))
ins.setBase(value);
});
}
}

View File

@ -1,9 +1,12 @@
package net.Indyuce.mmocore.api.player.profess;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.util.PostLoadObject;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import io.lumine.mythic.lib.script.Script;
@ -11,43 +14,42 @@ import io.lumine.mythic.lib.skill.SimpleSkill;
import io.lumine.mythic.lib.skill.Skill;
import io.lumine.mythic.lib.skill.handler.MythicLibSkillHandler;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import io.lumine.mythic.lib.util.FileUtils;
import io.lumine.mythic.lib.util.PostLoadAction;
import io.lumine.mythic.lib.util.PreloadedObject;
import io.lumine.mythic.lib.version.VParticle;
import io.lumine.mythic.lib.version.VersionMaterial;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.event.EventTrigger;
import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration;
import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
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.binding.SkillSlot;
import net.Indyuce.mmocore.skill.cast.ComboMap;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.logging.Level;
public class PlayerClass implements ExperienceObject, PreloadedObject {
public class PlayerClass extends PostLoadObject implements ExperienceObject {
private final String name, id, actionBarFormat;
private final List<String> description = new ArrayList<>(), attrDescription = new ArrayList<>();
private final ItemStack icon;
@ -66,7 +68,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
@Nullable
private final CastingParticle castParticle;
private final List<SkillSlot> skillSlots = new ArrayList<>();
private final Map<Integer, SkillSlot> skillSlots = new HashMap<>();
private final List<SkillTree> skillTrees = new ArrayList<>();
private final List<PassiveSkill> classScripts = new LinkedList();
private final Map<String, LinearValue> stats = new HashMap<>();
@ -80,32 +82,26 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
@Deprecated
private final Map<String, EventTrigger> eventTriggers = new HashMap<>();
private final PostLoadAction postLoadAction = new PostLoadAction(config -> {
if (config.contains("subclasses"))
for (String key : config.getConfigurationSection("subclasses").getKeys(false))
try {
subclasses.add(new Subclass(
MMOCore.plugin.classManager
.getOrThrow(key.toUpperCase().replace("-", "_").replace(" ", "_")),
config.getInt("subclasses." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load subclass '" + key + "' from class '"
+ getId() + "': " + exception.getMessage());
}
});
public PlayerClass(String id, ConfigurationSection config) {
postLoadAction.cacheConfig(config);
public PlayerClass(String id, FileConfiguration config) {
super(config);
this.id = id.toUpperCase().replace("-", "_").replace(" ", "_");
name = MythicLib.plugin.parseColors(config.getString("display.name", "INVALID DISPLAY NAME"));
icon = MMOCoreUtils.readIcon(config.getString("display.item", "BARRIER"));
if (config.contains("display.texture") && icon.getType() == Material.PLAYER_HEAD) {
if (config.contains("display.texture") && icon.getType() == VersionMaterial.PLAYER_HEAD.toMaterial())
try {
ItemMeta meta = icon.getItemMeta();
UtilityMethods.setTextureValue((SkullMeta) meta, config.getString("display.texture"));
Field profileField = meta.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
GameProfile gp = new GameProfile(UUID.randomUUID(), null);
gp.getProperties().put("textures", new Property("textures", config.getString("display.texture")));
profileField.set(meta, gp);
icon.setItemMeta(meta);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException
| SecurityException exception) {
throw new IllegalArgumentException("Could not apply playerhead texture: " + exception.getMessage());
}
for (String string : config.getStringList("display.lore"))
@ -188,13 +184,15 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
}
// Skill slots
if (config.isConfigurationSection("skill-slots"))
FileUtils.iterateConfigSectionList(
config.getConfigurationSection("skill-slots"),
skillSlots,
SkillSlot::new,
index -> new SkillSlot(index, 0, "true", "&eUnconfigured Skill Slot " + MMOCoreUtils.intToRoman(index), new ArrayList<>(), false, true, new ArrayList<>()),
(key, exception) -> MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load skill slot '" + key + "' from class '" + getId() + "': " + exception.getMessage()));
for (int i = 1; i < MMOCore.plugin.configManager.maxSkillSlots + 1; i++)
try {
if (config.contains("skill-slots." + i))
skillSlots.put(i, new SkillSlot(config.getConfigurationSection("skill-slots." + i)));
else
skillSlots.put(i, new SkillSlot(i, 0, "true", "&eSkill Slot " + MMOCoreUtils.intToRoman(i), new ArrayList<>(), false, true, new ArrayList<>()));
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load skill slot '" + String.valueOf(i) + "' from class '" + getId() + "': " + exception.getMessage());
}
// Class skills
for (RegisteredSkill registered : MMOCore.plugin.skillManager.getAll()) {
@ -258,6 +256,8 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
* option was not provided.
*/
public PlayerClass(String id, String name, Material material) {
super(null);
this.id = id;
this.name = name;
manaDisplay = ManaDisplayOptions.DEFAULT;
@ -266,7 +266,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
expCurve = ExpCurve.DEFAULT;
expTable = null;
comboMap = null;
castParticle = new CastingParticle(VParticle.INSTANT_EFFECT.get());
castParticle = new CastingParticle(Particle.SPELL_INSTANT);
actionBarFormat = "";
this.icon = new ItemStack(material);
setOption(ClassOption.DISPLAY, false);
@ -275,6 +275,21 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
resourceHandlers.put(resource, new ResourceRegeneration(resource));
}
@Override
protected void whenPostLoaded(ConfigurationSection config) {
if (config.contains("subclasses"))
for (String key : config.getConfigurationSection("subclasses").getKeys(false))
try {
subclasses.add(new Subclass(
MMOCore.plugin.classManager
.getOrThrow(key.toUpperCase().replace("-", "_").replace(" ", "_")),
config.getInt("subclasses." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load subclass '" + key + "' from class '"
+ getId() + "': " + exception.getMessage());
}
}
public String getId() {
return id;
}
@ -306,12 +321,6 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
return displayOrder;
}
@NotNull
@Override
public PostLoadAction getPostLoadAction() {
return postLoadAction;
}
@Override
public ExpCurve getExpCurve() {
return expCurve;
@ -427,21 +436,19 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
}
public boolean hasSlot(int slot) {
return 1 <= slot && slot <= skillSlots.size();
return skillSlots.containsKey(slot);
}
public List<SkillTree> getSkillTrees() {
return skillTrees;
}
@Nullable
public SkillSlot getSkillSlot(int slot) {
return hasSlot(slot) ? skillSlots.get(slot - 1) : null;
return skillSlots.get(slot);
}
@NotNull
public List<SkillSlot> getSlots() {
return skillSlots;
public Collection<SkillSlot> getSlots() {
return skillSlots.values();
}
@NotNull

View File

@ -5,7 +5,6 @@ import io.lumine.mythic.lib.gson.JsonObject;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.player.ClassDataContainer;
import net.Indyuce.mmocore.skill.RegisteredSkill;
@ -125,13 +124,13 @@ public class SavedClassInformation implements ClassDataContainer {
this.stellium = data.getStellium();
this.stamina = data.getStamina();
attributeLevels.putAll(data.mapAttributeLevels());
skillLevels.putAll(data.mapSkillLevels());
skillTreePoints.putAll(data.mapSkillTreePoints());
nodeLevels.putAll(data.getNodeLevels());
nodeTimesClaimed.putAll(data.getNodeTimesClaimed());
boundSkills.putAll(data.mapBoundSkills());
unlockedItems.addAll(data.getUnlockedItems());
data.mapAttributeLevels().forEach((key, val) -> this.attributeLevels.put(key, val));
data.mapSkillLevels().forEach((key, val) -> skillLevels.put(key, val));
data.mapSkillTreePoints().forEach((key, val) -> skillTreePoints.put(key, val));
data.getNodeLevels().forEach((node, level) -> nodeLevels.put(node, level));
data.getNodeTimesClaimed().forEach((key, val) -> nodeTimesClaimed.put(key, val));
data.mapBoundSkills().forEach((slot, skill) -> boundSkills.put(slot, skill));
data.getUnlockedItems().forEach(item -> unlockedItems.add(item));
}
@Override
@ -294,18 +293,22 @@ public class SavedClassInformation implements ClassDataContainer {
if (!player.getProfess().hasOption(ClassOption.DEFAULT) || MMOCore.plugin.configManager.saveDefaultClassInfo)
player.applyClassInfo(player.getProfess(), new SavedClassInformation(player));
// Remove class permanent buffs
player.getProfess().resetAdvancement(player, false);
// Remove perm stats for nodes and class
for (SkillTree skillTree : player.getProfess().getSkillTrees())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().removePermStats(player, node);
if (player.getProfess().hasExperienceTable())
player.getProfess().getExperienceTable().removePermStats(player, player.getProfess());
/*
* Resets information which much be reset after everything is saved.
*/
player.mapSkillLevels().forEach((skill, level) -> player.resetSkillLevel(skill));
for (PlayerAttribute attribute : MMOCore.plugin.attributeManager.getAll()) {
attribute.resetAdvancement(player, false);
player.getAttributes().getInstance(attribute).setBase(0);
}
player.resetSkillTrees();
player.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
player.clearSkillTreePoints();
player.clearNodeLevels();
player.clearNodeStates();
player.clearNodeTimesClaimed();
/*
* Reads this class info, applies it to the player. set class after
@ -324,7 +327,7 @@ public class SavedClassInformation implements ClassDataContainer {
player.bindSkill(slot, profess.getSkill(boundSkills.get(slot)));
skillLevels.forEach(player::setSkillLevel);
attributeLevels.forEach((id, pts) -> player.getAttributes().getInstance(id).setBase(pts));
attributeLevels.forEach((id, pts) -> player.getAttributes().setBaseAttribute(id, pts));
// Careful, the global points must not be forgotten.
player.setSkillTreePoints("global", skillTreePoints.getOrDefault("global", 0));
@ -339,17 +342,18 @@ public class SavedClassInformation implements ClassDataContainer {
// Add the values to the times claimed table and claims the corresponding stat triggers.
nodeTimesClaimed.forEach((str, val) -> player.setClaims(str, val));
// Unload current class information
player.unloadClassInfo(profess);
// This needs to be done at the end to make sure the MAX_HEALTH/MAX_MANA/... stats are loaded.
player.getPlayer().setHealth(MMOCoreUtils.fixResource(health, player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
player.setHealth(health);
player.setMana(mana);
player.setStellium(stellium);
player.setStamina(stamina);
player.applyTemporaryTriggers();
player.getStats().updateStats();
player.setupRemovableTrigger();
// Updates level on exp bar
player.refreshVanillaExp();
}
}

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.player.profess.event.trigger;
import io.lumine.mythic.lib.UtilityMethods;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockBreakEvent;
@ -18,8 +17,6 @@ public class BlockBrokenTrigger implements EventTriggerHandler {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void a(BlockBreakEvent event) {
if (UtilityMethods.isFake(event)) return;
PlayerData player = PlayerData.get(event.getPlayer());
if (player.getProfess().hasEventTriggers("break-block"))
player.getProfess().getEventTriggers("break-block").getTriggers().forEach(trigger -> trigger.apply(player));

View File

@ -1,6 +1,6 @@
package net.Indyuce.mmocore.api.player.social;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerActivity;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Sound;
@ -21,8 +21,8 @@ public class FriendRequest extends Request {
getCreator().addFriend(getTarget().getUniqueId());
getTarget().addFriend(getCreator().getUniqueId());
if (getCreator().isOnline()) {
ConfigMessage.fromKey("now-friends", "player", getTarget().getPlayer().getName()).send(getCreator().getPlayer());
ConfigMessage.fromKey("now-friends", "player", getCreator().getPlayer().getName()).send(getTarget().getPlayer());
MMOCore.plugin.configManager.getSimpleMessage("now-friends", "player", getTarget().getPlayer().getName()).send(getCreator().getPlayer());
MMOCore.plugin.configManager.getSimpleMessage("now-friends", "player", getCreator().getPlayer().getName()).send(getTarget().getPlayer());
}
}
}

View File

@ -8,13 +8,16 @@ import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import io.lumine.mythic.lib.player.skill.PassiveSkillMap;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class PlayerStats {
private final PlayerData data;
@ -46,7 +49,7 @@ public class PlayerStats {
}
public double getStat(String stat) {
return getMap().getStat(stat);
return getMap().getInstance(stat).getTotal();
}
/**
@ -67,24 +70,14 @@ public class PlayerStats {
return data.getProfess().calculateStat(stat, profession == null ? data.getLevel() : data.getCollectionSkills().getLevel(profession));
}
public void updateStats() {
updateStats(false);
}
/**
* Used to update MMOCore stat modifiers due to class and send them over to
* MythicLib. Must be ran everytime the player levels up, changes class or
* when the plugin reloads.
* MythicLib. Must be ran everytime the player levels up or changes class.
* <p>
* Login scripts are a pretty special case of scripts/skills since they are
* not loaded yet when MythicLib triggers them naturally. Therefore, they
* need to be cast as soon as they are loaded into the MMOCore player data.
*
* @param castLoginScripts Should login scripts be cast
* This is also called when reloading the plugin to make class setup easier,
* see {@link PlayerData#reload()} for more info
*/
public synchronized void updateStats(boolean castLoginScripts) {
// Update player stats
public synchronized void updateStats() {
for (String stat : MMOCore.plugin.statManager.getRegistered()) {
final StatInstance instance = getMap().getInstance(stat);
final StatInstance.ModifierPacket packet = instance.newPacket();
@ -101,32 +94,24 @@ public class PlayerStats {
packet.runUpdate();
}
// Updates the player's unbindable CLASS passive skills
/*
* This is here because it requires updates for the same reasons
* as statistics (when the player level changes, when his class
* changes, when he logs on..)
*
* This updates the player's PASSIVE skills
*/
final PassiveSkillMap skillMap = data.getMMOPlayerData().getPassiveSkillMap();
skillMap.removeModifiers("MMOCorePermanentSkill");
for (ClassSkill skill : data.getProfess().getSkills())
if (skill.isPermanent()
&& skill.getSkill().getTrigger() != TriggerType.LOGIN
&& data.hasUnlocked(skill)
&& data.hasUnlockedLevel(skill))
skillMap.addModifier(skill.toPassive(data));
// Updates the player's CLASS scripts
skillMap.removeModifiers("MMOCorePassiveSkillNotBound");
data.getProfess().getSkills()
.stream()
.filter((classSkill) -> !classSkill.needsBound()&&classSkill.getSkill().getTrigger().isPassive() && data.hasUnlocked(classSkill) && data.hasUnlockedLevel(classSkill))
.forEach(classSkill -> skillMap.addModifier(classSkill.toPassive(data)));
// This updates the player's class SCRIPTS
skillMap.removeModifiers("MMOCoreClassScript");
for (PassiveSkill script : data.getProfess().getScripts())
if (script.getType() != TriggerType.LOGIN) skillMap.addModifier(script);
// If data hasn't been synchronized yet, cast LOGIN scripts
if (castLoginScripts) {
// Call class login skills
for (ClassSkill skill : data.getProfess().getSkills())
if (skill.getSkill().getTrigger() == TriggerType.LOGIN)
skill.toCastable(data).cast(data.getMMOPlayerData());
// Call class login scripts
for (PassiveSkill skill : data.getProfess().getScripts())
if (skill.getType() == TriggerType.LOGIN) skill.getTriggeredSkill().cast(data.getMMOPlayerData());
}
skillMap.addModifier(script);
}
}

View File

@ -1,8 +1,8 @@
package net.Indyuce.mmocore.api.quest;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.gson.JsonElement;
import io.lumine.mythic.lib.gson.JsonObject;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.util.Closeable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
@ -99,7 +99,8 @@ public class PlayerQuests implements Closeable {
}
public void load(String json) {
JsonObject jo = MythicLib.plugin.getGson().fromJson(json, JsonObject.class);
Gson parser = new Gson();
JsonObject jo = parser.fromJson(json, JsonObject.class);
if (jo.has("current")) {
JsonObject cur = jo.getAsJsonObject("current");
try {

View File

@ -1,8 +1,12 @@
package net.Indyuce.mmocore.api.quest;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.util.PostLoadAction;
import io.lumine.mythic.lib.util.PreloadedObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.objective.Objective;
@ -10,32 +14,26 @@ import net.Indyuce.mmocore.experience.Profession;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.logging.Level;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.util.PostLoadObject;
public class Quest implements PreloadedObject {
private final String id, name;
public class Quest extends PostLoadObject {
private final String id;
private final String name;
private final List<Quest> parents = new ArrayList<>();
private final List<Objective> objectives = new ArrayList<>();
private final List<String> lore;
private final int mainLevelRestriction;
private final Map<Profession, Integer> levelRestrictions = new HashMap<>();
// Cooldown in millis
// cooldown in millis
private final long cooldown;
private final PostLoadAction postLoadAction = new PostLoadAction(config -> {
// Load parent quests
if (config.contains("parent"))
for (String parent : config.getStringList("parent"))
parents.add(MMOCore.plugin.questManager.getOrThrow(parent.toLowerCase().replace(" ", "-").replace("_", "-")));
});
public Quest(String id, ConfigurationSection config) {
postLoadAction.cacheConfig(config);
public Quest(String id, FileConfiguration config) {
super(config);
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
cooldown = (long) (config.contains("delay") ? config.getDouble("delay") * 60 * 60 * 1000 : -1);
@ -71,10 +69,11 @@ public class Quest implements PreloadedObject {
}
}
@NotNull
@Override
public PostLoadAction getPostLoadAction() {
return postLoadAction;
protected void whenPostLoaded(ConfigurationSection config) {
if (config.contains("parent"))
for (String parent : config.getStringList("parent"))
parents.add(MMOCore.plugin.questManager.getOrThrow(parent.toLowerCase().replace(" ", "-").replace("_", "-")));
}
public String getId() {

View File

@ -46,19 +46,19 @@ public class QuestProgress {
public void completeObjective() {
objective++;
objectiveProgress.close();
final ObjectiveProgress finishedObjectiveProgress = objectiveProgress;
// Start next objective, or end quest.
if (objective >= quest.getObjectives().size()) player.getQuestData().finishCurrent();
else objectiveProgress = nextObjective().newProgress(this);
// end quest
if (objective >= quest.getObjectives().size())
player.getQuestData().finishCurrent();
else
objectiveProgress = nextObjective().newProgress(this);
player.getQuestData().updateBossBar();
/*
* Apply triggers only at the end! It comes handy when starting another
* quest in some storyline using triggers from the previous quest.
*/
finishedObjectiveProgress.getObjective().getTriggers().forEach(trigger -> trigger.schedule(getPlayer()));
// apply triggers at the end so the quest is ended when a trigger quest start is launched.
objectiveProgress.getObjective().getTriggers().forEach(trigger -> trigger.schedule(getPlayer()));
}
public String getFormattedLore() {

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.objective;
import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.api.quest.ObjectiveProgress;
import net.Indyuce.mmocore.api.event.CustomBlockMineEvent;
import net.Indyuce.mmocore.api.quest.QuestProgress;
@ -43,8 +42,6 @@ public class MineBlockObjective extends Objective {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(BlockBreakEvent event) {
if(!getQuestProgress().getPlayer().isOnline()) return;
if (UtilityMethods.isFake(event)) return;
if ((!playerPlaced) && event.getBlock().hasMetadata("player_placed"))
return;
if (event.getPlayer().equals(getQuestProgress().getPlayer().getPlayer()) && event.getBlock().getType() == block) {

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import javax.annotation.Nullable;
import java.util.Objects;
public class BindSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill;
@ -18,13 +19,14 @@ public class BindSkillTrigger extends Trigger implements Removable {
config.validateKeys("skill", "slot");
slot = config.getInt("slot");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill"));
skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
}
@Override
public void apply(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill);
if (found != null) playerData.bindSkill(slot, found);
if (found != null)
playerData.bindSkill(slot, found);
}
@Override

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Bukkit;
@ -24,9 +23,7 @@ public class CommandTrigger extends Trigger {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), format(player.getPlayer()));
}
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
private String format(Player player) {
// TODO remove use of confusing non-PAPI %player% placeholder
return MMOCore.plugin.placeholderParser.parse(player, command.replace("%player%", player.getName()));
}
}

View File

@ -6,6 +6,8 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import java.util.Objects;
public class LevelUpSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill;
private final int amount;
@ -15,7 +17,7 @@ public class LevelUpSkillTrigger extends Trigger implements Removable {
config.validateKeys("skill", "amount");
amount = config.getInt("amount");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill"));
skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
}
@Override

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.entity.Player;
@ -23,9 +22,7 @@ public class MessageTrigger extends Trigger {
player.getPlayer().sendMessage(format(player.getPlayer()));
}
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
private String format(Player player) {
// TODO remove use of confusing non-PAPI %player% placeholder
return MMOCore.plugin.placeholderParser.parse(player, message.replace("%player%", player.getName()));
}
}

View File

@ -8,17 +8,16 @@ import io.lumine.mythic.lib.skill.handler.SkillHandler;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.quest.trigger.api.Temporary;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.UUID;
public class SkillModifierTrigger extends Trigger implements Removable, Temporary {
private SkillModifier mod;
private boolean mutable = true;
public class SkillModifierTrigger extends Trigger implements Removable {
private final SkillModifier mod;
private final String buffKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount;
public SkillModifierTrigger(MMOLineConfig config) {
super(config);
@ -26,18 +25,16 @@ public class SkillModifierTrigger extends Trigger implements Removable, Temporar
config.validateKeys("modifier");
config.validateKeys("amount");
final double amount = config.getDouble("amount");
final String parameter = config.getString("modifier");
amount = config.getDouble("amount");
final String skillModifier = config.getString("modifier");
final String formula = config.getString("formula", "true");
final ModifierType type = config.contains("type") ? ModifierType.valueOf(UtilityMethods.enumName(config.getString("type"))) : ModifierType.FLAT;
final List<SkillHandler<?>> targetSkills = MMOCore.plugin.skillManager.getAll().stream().filter(skill -> skill.matchesFormula(formula)).map(RegisteredSkill::getHandler).collect(Collectors.toList());
List<SkillHandler<?>> targetSkills = new ArrayList<>();
for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll())
if (skill.matchesFormula(formula))
targetSkills.add(skill.getHandler());
mod = new SkillModifier(Trigger.STAT_MODIFIER_KEY, parameter, targetSkills, amount, type);
}
public void updateKey(@NotNull String key) {
Validate.isTrue(mutable, "No longer mutable");
this.mod = new SkillModifier(key, mod.getParameter(), mod.getSkills(), mod.getValue(), mod.getType());
mod = new SkillModifier(buffKey, skillModifier, targetSkills, amount, type);
}
public List<SkillHandler<?>> getTargetSkills() {
@ -59,7 +56,6 @@ public class SkillModifierTrigger extends Trigger implements Removable, Temporar
* to a dynamically chosen skill handler.
*/
public void apply(PlayerData playerData, SkillHandler<?> skill) {
mutable = false;
mod.register(playerData.getMMOPlayerData(), skill);
}

View File

@ -5,12 +5,14 @@ import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.quest.trigger.api.Temporary;
import org.apache.commons.lang.Validate;
public class StatTrigger extends Trigger implements Removable, Temporary {
private final StatModifier modifier;
import java.util.UUID;
public class StatTrigger extends Trigger implements Removable {
private final StatModifier statModifier;
private final String stat;
private final String modifierKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount;
public StatTrigger(MMOLineConfig config) {
@ -23,18 +25,22 @@ public class StatTrigger extends Trigger implements Removable, Temporary {
Validate.isTrue(type.equals("FLAT") || type.equals("RELATIVE"));
stat = config.getString("stat");
amount = config.getDouble("amount");
modifier = new StatModifier(Trigger.STAT_MODIFIER_KEY, stat, amount, ModifierType.valueOf(type));
statModifier = new StatModifier(modifierKey, stat, amount, ModifierType.valueOf(type));
}
@Override
public void apply(PlayerData player) {
StatModifier prevModifier = player.getMMOPlayerData().getStatMap().getInstance(stat).getModifier(modifier.getUniqueId());
if (prevModifier == null) modifier.register(player.getMMOPlayerData());
else prevModifier.add(amount).register(player.getMMOPlayerData());
StatModifier prevModifier = player.getMMOPlayerData().getStatMap().getInstance(stat).getModifier(modifierKey);
if (prevModifier == null)
statModifier.register(player.getMMOPlayerData());
else {
prevModifier.unregister(player.getMMOPlayerData());
prevModifier.add(amount).register(player.getMMOPlayerData());
}
}
@Override
public void remove(PlayerData playerData) {
modifier.unregister(playerData.getMMOPlayerData());
playerData.getMMOPlayerData().getStatMap().getInstance(stat).remove(modifierKey);
}
}

View File

@ -7,7 +7,7 @@ import org.bukkit.Bukkit;
public abstract class Trigger {
public static String STAT_MODIFIER_KEY = "mmocore_trigger";
public static String TRIGGER_PREFIX = "mmocore_trigger";
private final long delay;
public Trigger(MMOLineConfig config) {

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import javax.annotation.Nullable;
import java.util.Objects;
public class UnlockSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill;
@ -16,18 +17,20 @@ public class UnlockSkillTrigger extends Trigger implements Removable {
super(config);
config.validateKeys("skill");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill"));
skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
}
@Override
public void apply(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill);
if (found != null) playerData.unlock(found);
if (found != null)
playerData.unlock(found);
}
@Override
public void remove(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill);
if (found != null) playerData.lock(found);
if (found != null)
playerData.lock(found);
}
}

View File

@ -13,23 +13,26 @@ public class UnlockSlotTrigger extends Trigger implements Removable {
public UnlockSlotTrigger(MMOLineConfig config) {
super(config);
config.validateKeys("slot");
try {
slot = Integer.parseInt(config.getString("slot"));
} catch (NumberFormatException exception) {
throw new IllegalArgumentException("Slot should be a number");
}catch(NumberFormatException e){
throw new IllegalArgumentException("The slot should be a number");
}
Validate.isTrue(slot > 0, "Slot number must be positive");
Validate.isTrue(slot > 0 && slot <= MMOCore.plugin.configManager.maxSkillSlots, "The slot should be between 1 and " + MMOCore.plugin.configManager.maxSkillSlots);
}
@Override
public void apply(PlayerData player) {
player.unlock(player.getProfess().getSkillSlot(slot));
final SkillSlot skillSlot = player.getProfess().getSkillSlot(slot);
if (!player.hasUnlocked(skillSlot))
player.unlock(skillSlot);
}
@Override
public void remove(PlayerData player) {
player.lock(player.getProfess().getSkillSlot(slot));
final SkillSlot skillSlot = player.getProfess().getSkillSlot(slot);
if (player.hasUnlocked(skillSlot))
player.lock(skillSlot);
}
}

View File

@ -2,12 +2,6 @@ package net.Indyuce.mmocore.api.quest.trigger.api;
import net.Indyuce.mmocore.api.player.PlayerData;
/**
* Cancelable triggers cause problems when letting the player reset
* their advancement on things they can spend points in/level up.
* If you give access to some resource to the player via a trigger,
* you must take it away when resetting their progression.
*/
public interface Removable {
public void remove(PlayerData playerData);
}

View File

@ -1,12 +0,0 @@
package net.Indyuce.mmocore.api.quest.trigger.api;
/**
* Non-permanent triggers are triggers which are not saved
* by the player and taken off when the player logs off,
* for instance temporary player modifiers. They need to
* be re-applied everytime the player logs back.
*
* @author jules
*/
public interface Temporary extends Removable {
}

View File

@ -1,14 +1,15 @@
package net.Indyuce.mmocore.api.util;
import com.google.common.collect.MultimapBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.gson.JsonArray;
import io.lumine.mythic.lib.gson.JsonObject;
import io.lumine.mythic.lib.hologram.Hologram;
import io.lumine.mythic.lib.version.VEnchantment;
import io.lumine.mythic.lib.version.VersionMaterial;
import net.Indyuce.mmocore.MMOCore;
import org.bukkit.*;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
@ -17,13 +18,11 @@ import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream;
@ -35,24 +34,9 @@ public class MMOCoreUtils {
return item != null && item.hasItemMeta() && item.getItemMeta().hasDisplayName();
}
/**
* If a given player is not in the server cache, no information
* cannot be retrieved from that player (without using requests
* to MC servers obviously). In that case, the instance of
* OfflinePlayer is pretty much useless and it only wraps its
* UUID which was already known beforehand.
*
* @param player Offline player instance to test
* @return Is the instance valid
*/
public static boolean isInvalid(OfflinePlayer player) {
return player.getName() == null;
}
@Deprecated
public static String displayName(ItemStack item) {
return item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName()
: UtilityMethods.caseOnWords(item.getType().name().replace("_", " "));
: caseOnWords(item.getType().name().replace("_", " "));
}
/**
@ -65,7 +49,6 @@ public class MMOCoreUtils {
return current == 0 ? maxStat : Math.max(0, Math.min(current, maxStat));
}
@Deprecated
public static String caseOnWords(String s) {
StringBuilder builder = new StringBuilder(s);
boolean isLastSpace = true;
@ -84,9 +67,32 @@ public class MMOCoreUtils {
return str.toLowerCase().replace("_", "-").replace(" ", "-");
}
@Deprecated
/**
* @param value an integer you want to convert
* @return the string representing the integer but with roman letters
*/
public static String toRomanNumerals(int value) {
return intToRoman(value);
LinkedHashMap<String, Integer> roman_numerals = new LinkedHashMap<String, Integer>();
roman_numerals.put("M", 1000);
roman_numerals.put("CM", 900);
roman_numerals.put("D", 500);
roman_numerals.put("CD", 400);
roman_numerals.put("C", 100);
roman_numerals.put("XC", 90);
roman_numerals.put("L", 50);
roman_numerals.put("XL", 40);
roman_numerals.put("X", 10);
roman_numerals.put("IX", 9);
roman_numerals.put("V", 5);
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();
res += repeat(entry.getKey(), matches);
value = value % entry.getValue();
}
return res;
}
private static String repeat(String s, int n) {
@ -110,38 +116,18 @@ public class MMOCoreUtils {
* @param message Message to display
*/
public static void displayIndicator(Location loc, String message) {
Hologram holo = Hologram.create(loc, MythicLib.plugin.parseColors(Collections.singletonList(message)));
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, holo::despawn, 20);
Hologram holo = Hologram.create(loc, Arrays.asList(message));
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, () -> holo.despawn(), 20);
}
public static boolean isPlayerHead(Material material) {
return material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD;
return material == VersionMaterial.PLAYER_HEAD.toMaterial() || material == VersionMaterial.PLAYER_WALL_HEAD.toMaterial();
}
public static void addAllItemFlags(@NotNull ItemMeta meta) {
meta.addItemFlags(ItemFlag.values());
// Fix 1.20.6+ Paper bug that sucks. HIDE_ATTRIBUTES no longer works when item attribute list is empty
// TODO refactor with GUI update.
try {
meta.setAttributeModifiers(MultimapBuilder.hashKeys(0).hashSetValues(0).build());
} catch (Exception exception) {
// Not needed
}
}
@NotNull
public static ItemStack readIcon(String string) {
final String[] split = string.split(":");
final ItemStack item = new ItemStack(Material.valueOf(split[0].toUpperCase().replace("-", "_").replace(" ", "_")));
if (split.length > 1) {
final ItemMeta meta = item.getItemMeta();
meta.setCustomModelData(Integer.parseInt(split[1]));
item.setItemMeta(meta);
}
return item;
public static ItemStack readIcon(String string) throws IllegalArgumentException {
String[] split = string.split(":");
Material material = Material.valueOf(split[0].toUpperCase().replace("-", "_").replace(" ", "_"));
return split.length > 1 ? MythicLib.plugin.getVersion().getWrapper().textureItem(material, Integer.parseInt(split[1])) : new ItemStack(material);
}
public static int getWorth(ItemStack[] items) {
@ -257,7 +243,6 @@ public class MMOCoreUtils {
return entities;
}
@Deprecated
public static void heal(LivingEntity target, double value) {
double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
double gain = Math.min(max, target.getHealth() + value) - target.getHealth();
@ -268,8 +253,6 @@ public class MMOCoreUtils {
target.setHealth(target.getHealth() + gain);
}
private static final Random RANDOM = new Random();
/**
* Method used when mining a custom block or fishing, as the corresponding
* interaction event is cancelled durability is not handled. This method is
@ -285,20 +268,16 @@ public class MMOCoreUtils {
*/
public static void decreaseDurability(Player player, EquipmentSlot slot, int damage) {
ItemStack item = UtilityMethods.getHandItem(player, slot);
ItemStack item = player.getInventory().getItem(slot);
if (item == null || item.getType().getMaxDurability() == 0 || item.getItemMeta().isUnbreakable())
return;
// Check unbreakable, ignore if necessary
final ItemMeta meta = item.getItemMeta();
final int unbreakingLevel = meta.getEnchantLevel(VEnchantment.UNBREAKING.get());
if (unbreakingLevel > 0 && RANDOM.nextInt(unbreakingLevel + 1) != 0) return;
PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, item, damage);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
ItemMeta meta = item.getItemMeta();
final int newDamage = event.getDamage() + ((Damageable) meta).getDamage();
if (newDamage >= item.getType().getMaxDurability()) {
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1F, 1F);
@ -315,11 +294,4 @@ public class MMOCoreUtils {
public static Location getCenterLocation(Entity entity) {
return entity.getBoundingBox().getCenter().toLocation(entity.getWorld());
}
public static void debug(String message) {
message = ChatColor.YELLOW + "Debug> " + ChatColor.WHITE + message;
for (Player player : Bukkit.getOnlinePlayers())
player.sendMessage(message);
Bukkit.getConsoleSender().sendMessage(message);
}
}

View File

@ -1,7 +1,6 @@
package net.Indyuce.mmocore.api.util.input;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.MMOCore;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -13,6 +12,8 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.Consumer;
import io.lumine.mythic.lib.MythicLib;
@Deprecated
public class AnvilGUI extends PlayerInput {
private final int containerId;
@ -23,7 +24,7 @@ public class AnvilGUI extends PlayerInput {
ItemStack paper = new ItemStack(Material.PAPER);
ItemMeta paperMeta = paper.getItemMeta();
paperMeta.setDisplayName(ConfigMessage.fromKey("player-input.anvil." + type.getLowerCaseName()).asLine());
paperMeta.setDisplayName(MMOCore.plugin.configManager.getSimpleMessage("player-input.anvil." + type.getLowerCaseName()).message());
paper.setItemMeta(paperMeta);
MythicLib.plugin.getVersion().getWrapper().handleInventoryCloseEvent(player);

View File

@ -1,8 +1,7 @@
package net.Indyuce.mmocore.api.util.input;
import io.lumine.mythic.lib.gui.framework.PluginInventory;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.gui.api.PluginInventory;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -38,7 +37,8 @@ public class ChatInput extends PlayerInput {
this.lastOpened = lastOpened;
player.closeInventory();
ConfigMessage.fromKey("player-input.chat." + inputType.getLowerCaseName()).send(player);
MMOCore.plugin.configManager.getSimpleMessage("player-input.chat." + inputType.getLowerCaseName()).send(player);
MMOCore.plugin.configManager.getSimpleMessage("player-input.chat.cancel").send(player);
}
@Override
@ -56,7 +56,7 @@ public class ChatInput extends PlayerInput {
if (event.getMessage().equals("cancel")) {
if (lastOpened != null)
Bukkit.getScheduler().runTask(MMOCore.plugin, () -> lastOpened.open());
ConfigMessage.fromKey("player-input.chat." + inputType.getLowerCaseName() + "-cancel").send(getPlayer());
MMOCore.plugin.configManager.getSimpleMessage("player-input.chat." + inputType.getLowerCaseName() + "-cancel").send(getPlayer());
} else
// Run sync
Bukkit.getScheduler().runTask(MMOCore.plugin, () -> output(event.getMessage()));

View File

@ -29,6 +29,7 @@ public abstract class PlayerInput implements Listener {
public enum InputType {
FRIEND_REQUEST,
PARTY_INVITE,
GUILD_INVITE,
GUILD_CREATION_TAG,

View File

@ -29,7 +29,7 @@ public class AttributesCommand extends RegisteredCommand {
PlayerData data = PlayerData.get((Player) sender);
MMOCommandEvent event = new MMOCommandEvent(data, "attributes");
Bukkit.getServer().getPluginManager().callEvent(event);
if(!event.isCancelled()) InventoryManager.ATTRIBUTE_VIEW.newInventory(data).open();
if(!event.isCancelled()) InventoryManager.ATTRIBUTE_VIEW.generate(data,null).open();
return true;
}
}

View File

@ -32,9 +32,9 @@ public class ClassCommand extends RegisteredCommand {
Bukkit.getServer().getPluginManager().callEvent(event);
if(event.isCancelled()) return true;
if (data.getProfess().getSubclasses().stream().anyMatch(sub -> sub.getLevel() <= data.getLevel()))
InventoryManager.SUBCLASS_SELECT.newInventory(data).open();
InventoryManager.SUBCLASS_SELECT.generate(data,null).open();
else
InventoryManager.CLASS_SELECT.newInventory(data).open();
InventoryManager.CLASS_SELECT.generate(data,null).open();
return true;
}
}

View File

@ -27,7 +27,7 @@ public class DepositCommand extends RegisteredCommand {
// if (sender instanceof Player)
// if (!isNearEnderchest(((Player) sender).getLocation())) {
// sender.sendMessage(ConfigMessage.fromKey("stand-near-enderchest"));
// sender.sendMessage(MMOCore.plugin.configManager.getSimpleMessage("stand-near-enderchest"));
// return true;
// }

View File

@ -68,7 +68,7 @@ public class FriendsCommand extends RegisteredCommand {
return true;
}
InventoryManager.FRIEND_LIST.newInventory(data).open();
InventoryManager.FRIEND_LIST.generate(data,null).open();
return true;
}
}

View File

@ -49,7 +49,7 @@ public class GuildCommand extends RegisteredCommand {
final Request req = MMOCore.plugin.requestManager.getRequest(uuid);
Validate.isTrue(!req.isTimedOut() && req instanceof GuildInvite);
invite = (GuildInvite) req;
Validate.isTrue(MMOCore.plugin.nativeGuildManager.isRegistered(invite.getGuild()));
Validate.isTrue(MMOCore.plugin.dataProvider.getGuildManager().isRegistered(invite.getGuild()));
} catch (Exception exception) {
return true;
}
@ -70,9 +70,9 @@ public class GuildCommand extends RegisteredCommand {
}
if (data.inGuild())
InventoryManager.GUILD_VIEW.newInventory(data).open();
InventoryManager.GUILD_VIEW.generate(data, null).open();
else
InventoryManager.GUILD_CREATION.newInventory(data).open();
InventoryManager.GUILD_CREATION.generate(data, null).open();
return true;
}
}

View File

@ -74,9 +74,9 @@ public class PartyCommand extends RegisteredCommand {
}
if (data.getParty() != null)
InventoryManager.PARTY_VIEW.newInventory(data).open();
InventoryManager.PARTY_VIEW.generate(data,null).open();
else
InventoryManager.PARTY_CREATION.newInventory(data).open();
InventoryManager.PARTY_CREATION.generate(data,null).open();
return true;
}
}

View File

@ -28,7 +28,7 @@ public class PlayerStatsCommand extends RegisteredCommand {
PlayerData data = PlayerData.get((Player) sender);
MMOCommandEvent event = new MMOCommandEvent(data, "profile");
Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) InventoryManager.PLAYER_STATS.newInventory(data).open();
if (!event.isCancelled()) InventoryManager.PLAYER_STATS.generate(data, null).open();
return true;
}
}

View File

@ -3,7 +3,6 @@ package net.Indyuce.mmocore.command;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand;
@ -27,7 +26,7 @@ public class PvpModeCommand extends RegisteredCommand {
}
if (!sender.hasPermission("mmocore.pvpmode")) {
ConfigMessage.fromKey("not-enough-perms").send((Player) sender);
MMOCore.plugin.configManager.getSimpleMessage("not-enough-perms").send((Player) sender);
return false;
}
@ -35,7 +34,7 @@ public class PvpModeCommand extends RegisteredCommand {
// Command cooldown
if (playerData.getCooldownMap().isOnCooldown(COOLDOWN_KEY)) {
ConfigMessage.fromKey("pvp-mode.cooldown", "remaining", MythicLib.plugin.getMMOConfig().decimal.format(playerData.getCooldownMap().getCooldown(COOLDOWN_KEY))).send((Player) sender);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cooldown", "remaining", MythicLib.plugin.getMMOConfig().decimal.format(playerData.getCooldownMap().getCooldown(COOLDOWN_KEY))).send((Player) sender);
return true;
}
@ -46,12 +45,12 @@ public class PvpModeCommand extends RegisteredCommand {
if (playerData.getCombat().isInPvpMode() &&
MythicLib.plugin.getFlags().isFlagAllowed(playerData.getPlayer(), CustomFlag.PVP_MODE)) {
playerData.getCombat().setInvulnerable(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand);
ConfigMessage.fromKey("pvp-mode.toggle.on-invulnerable", "time",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.toggle.on-invulnerable", "time",
MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand)).send(playerData.getPlayer());
// Just send message otherwise
} else
ConfigMessage.fromKey("pvp-mode.toggle." + (playerData.getCombat().isInPvpMode() ? "on" : "off") + "-safe").send((Player) sender);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.toggle." + (playerData.getCombat().isInPvpMode() ? "on" : "off") + "-safe").send((Player) sender);
return true;
}
}

View File

@ -23,7 +23,7 @@ public class QuestsCommand extends RegisteredCommand {
PlayerData data = PlayerData.get((Player) sender);
MMOCommandEvent event = new MMOCommandEvent(data, "quests");
Bukkit.getServer().getPluginManager().callEvent(event);
if(!event.isCancelled()) InventoryManager.QUEST_LIST.newInventory(data).open();
if(!event.isCancelled()) InventoryManager.QUEST_LIST.generate(data,null).open();
}
return true;
}

View File

@ -2,9 +2,8 @@ package net.Indyuce.mmocore.command;
import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand;
import net.Indyuce.mmocore.manager.InventoryManager;
@ -20,15 +19,16 @@ import java.util.stream.Collectors;
public class SkillTreesCommand extends RegisteredCommand {
public SkillTreesCommand(ConfigurationSection config) {
super(config, ToggleableCommand.SKILL_TREES);
}
@Override
public boolean execute(@NotNull CommandSender sender, String s, String[] args) {
if (!sender.hasPermission("mmocore.skilltrees"))
return false;
if (!(sender instanceof Player))
if (!(sender instanceof Player player))
return false;
final Player player = (Player) sender;
PlayerData data = PlayerData.get(player);
MMOCommandEvent event = new MMOCommandEvent(data, "skilltrees");
Bukkit.getServer().getPluginManager().callEvent(event);
@ -42,10 +42,10 @@ public class SkillTreesCommand extends RegisteredCommand {
return false;
}
if (data.getProfess().getSkillTrees().size() != 0) {
InventoryManager.TREE_VIEW.newInventory(data).open();
InventoryManager.TREE_VIEW.generate(data, null).open();
return true;
} else {
ConfigMessage.fromKey("no-skill-tree").send(player);
MMOCore.plugin.configManager.getSimpleMessage("no-skill-tree").send(player);
return false;
}
}
@ -60,7 +60,7 @@ public class SkillTreesCommand extends RegisteredCommand {
.filter(skillTree -> UtilityMethods.ymlName(skillTree.getId()).equals(UtilityMethods.ymlName(args[0])))
.collect(Collectors.toList())
.size() != 0) {
InventoryManager.SPECIFIC_TREE_VIEW.get(UtilityMethods.ymlName(args[0])).newInventory(data).open();
InventoryManager.SPECIFIC_TREE_VIEW.get(UtilityMethods.ymlName(args[0])).generate(data, null).open();
return true;
} else {
sender.sendMessage(ChatColor.RED + "Your class does not have a skill tree with id: " + args[0]);
@ -73,5 +73,7 @@ public class SkillTreesCommand extends RegisteredCommand {
sender.sendMessage(ChatColor.RED + "Usage: /skilltrees");
return false;
}
}
}

View File

@ -1,11 +1,11 @@
package net.Indyuce.mmocore.command;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand;
import net.Indyuce.mmocore.manager.InventoryManager;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
@ -27,11 +27,11 @@ public class SkillsCommand extends RegisteredCommand {
if(event.isCancelled()) return true;
if (data.getUnlockedSkills().isEmpty()) {
ConfigMessage.fromKey("no-class-skill").send((Player) sender);
MMOCore.plugin.configManager.getSimpleMessage("no-class-skill").send((Player) sender);
return true;
}
InventoryManager.SKILL_LIST.newInventory(data).open();
InventoryManager.SKILL_LIST.generate(data,null).open();
}
return true;
}

View File

@ -21,7 +21,7 @@ public class WaypointsCommand extends RegisteredCommand {
PlayerData data = PlayerData.get((Player) sender);
MMOCommandEvent event = new MMOCommandEvent(data, "waypoints");
Bukkit.getServer().getPluginManager().callEvent(event);
if(!event.isCancelled()) InventoryManager.WAYPOINTS.newInventory(data).open();
if (!event.isCancelled()) InventoryManager.WAYPOINTS.generate(data, null).open();
}
return true;
}

View File

@ -1,8 +1,6 @@
package net.Indyuce.mmocore.command;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.eco.Withdraw;
import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand;
import org.apache.commons.lang.Validate;
@ -13,6 +11,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import net.Indyuce.mmocore.api.eco.Withdraw;
public class WithdrawCommand extends RegisteredCommand {
public WithdrawCommand(ConfigurationSection config) {
super(config, ToggleableCommand.WITHDRAW);
@ -37,7 +37,7 @@ public class WithdrawCommand extends RegisteredCommand {
amount = Integer.parseInt(amountArgument);
Validate.isTrue(amount >= 0);
} catch (IllegalArgumentException exception) {
sender.sendMessage(ConfigMessage.fromKey("wrong-number", "arg", "" + args[0]).asLine());
sender.sendMessage(MMOCore.plugin.configManager.getSimpleMessage("wrong-number", "arg", "" + args[0]).message());
return true;
}
@ -50,14 +50,14 @@ public class WithdrawCommand extends RegisteredCommand {
int left = (int) MMOCore.plugin.economy.getEconomy().getBalance(player) - amount;
if (left < 0) {
ConfigMessage.fromKey("not-enough-money", "left", "" + -left).send(player);
MMOCore.plugin.configManager.getSimpleMessage("not-enough-money", "left", "" + -left).send(player);
return true;
}
MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, amount);
request.withdrawAlgorythm(amount);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1);
ConfigMessage.fromKey("withdrew", "worth", amount).send(player);
MMOCore.plugin.configManager.getSimpleMessage("withdrew", "worth", "" + amount).send(player);
return true;
}
}

View File

@ -29,7 +29,7 @@ public class AdminCommandTreeNode extends CommandTreeNode {
addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints));
addChild(new PointsCommandTreeNode("skill-realloc", this, PlayerData::setSkillReallocationPoints, PlayerData::giveSkillReallocationPoints, PlayerData::getSkillReallocationPoints));
addChild(new PointsCommandTreeNode("skill-tree-realloc", this, PlayerData::setSkillTreeReallocationPoints, PlayerData::giveSkillTreeReallocationPoints, PlayerData::getSkillTreeReallocationPoints));
addChild(new SkillTreePointsCommandTreeNode(this, (playerData, integer, s) -> playerData.setSkillTreePoints(s, integer), (playerData, integer, s) -> playerData.giveSkillTreePoints(s, integer), PlayerData::getSkillTreePoints));
addChild(new SkillTreePointsCommandTreeNode(this, (playerData, integer, s) -> playerData.setSkillTreePoints(s, integer), (playerData, integer, s) -> playerData.giveSkillTreePoints(s, integer), ((playerData, s) -> playerData.getSkillTreePoint(s))));
for (PlayerResource res : PlayerResource.values())
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
}

View File

@ -1,20 +1,20 @@
package net.Indyuce.mmocore.command.rpg.admin;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.command.api.CommandVerbose;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.command.api.CommandVerbose;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
public class ClassCommandTreeNode extends CommandTreeNode {
public ClassCommandTreeNode(CommandTreeNode parent) {
super(parent, "class");
@ -52,9 +52,9 @@ public class ClassCommandTreeNode extends CommandTreeNode {
return CommandResult.SUCCESS;
(data.hasSavedClass(profess) ? data.getClassInfo(profess)
: new SavedClassInformation(MMOCore.plugin.playerDataManager.getDefaultData())).load(profess, data);
: new SavedClassInformation(MMOCore.plugin.dataProvider.getDataManager().getDefaultData())).load(profess, data);
if (data.isOnline()) {
ConfigMessage.fromKey("class-select", "class", profess.getName()).send(data.getPlayer());
MMOCore.plugin.configManager.getSimpleMessage("class-select", "class", profess.getName()).send(data.getPlayer());
data.getPlayer().playSound(data.getPlayer().getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1, 1);
}

View File

@ -1,13 +1,22 @@
package net.Indyuce.mmocore.command.rpg.admin;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.data.DataExport;
import io.lumine.mythic.lib.data.sql.SQLDataSource;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.manager.data.sql.SQLDataHandler;
import net.Indyuce.mmocore.manager.data.yaml.YAMLPlayerDataHandler;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.stream.Collectors;
/**
* This command allows to transfer data from your actual storage type
@ -18,15 +27,82 @@ public class ExportDataTreeNode extends CommandTreeNode {
super(parent, "exportdata");
}
/**
* Amount of requests generated every batch
*/
private static final int BATCH_AMOUNT = 50;
/**
* Period in ticks
*/
private static final int BATCH_PERIOD = 20;
private static final DecimalFormat decFormat = new DecimalFormat("0.#");
@Override
@NotNull
public CommandResult execute(CommandSender sender, String[] strings) {
// Export YAML to SQL
final boolean result = new DataExport<>(MMOCore.plugin.playerDataManager, sender).start(
() -> new YAMLPlayerDataHandler(MMOCore.plugin),
() -> new SQLDataHandler(new SQLDataSource(MMOCore.plugin)));
if (!MMOCore.plugin.dataProvider.getDataManager().getLoaded().isEmpty()) {
sender.sendMessage("Please make sure no players are logged in when using this command. " +
"If you are still seeing this message, restart your server and execute this command before any player logs in.");
return CommandResult.FAILURE;
}
return result ? CommandResult.SUCCESS : CommandResult.FAILURE;
final List<UUID> playerIds = Arrays.stream(new File(MMOCore.plugin.getDataFolder() + "/userdata").listFiles())
.map(file -> UUID.fromString(file.getName().replace(".yml", ""))).collect(Collectors.toList());
// Initialize fake SQL data provider
final SQLDataHandler sqlHandler;
try {
sqlHandler = new SQLDataHandler(new SQLDataSource(MMOCore.plugin));
} catch (RuntimeException exception) {
sender.sendMessage("Could not initialize SQL provider (see console for stack trace): " + exception.getMessage());
return CommandResult.FAILURE;
}
final double timeEstimation = (double) playerIds.size() / BATCH_AMOUNT * BATCH_PERIOD / 20;
sender.sendMessage("Exporting " + playerIds.size() + " player data(s).. See console for details");
sender.sendMessage("Minimum expected time: " + decFormat.format(timeEstimation) + "s");
// Save player data
new BukkitRunnable() {
int errorCount = 0;
int batchCounter = 0;
@Override
public void run() {
for (int i = 0; i < BATCH_AMOUNT; i++) {
final int index = BATCH_AMOUNT * batchCounter + i;
/*
* Saving is done. Close connection to avoid memory
* leaks and ouput the results to the command executor
*/
if (index >= playerIds.size()) {
cancel();
sqlHandler.close();
MMOCore.plugin.getLogger().log(Level.WARNING, "Exported " + playerIds.size() + " player datas to SQL database. Total errors: " + errorCount);
return;
}
final UUID playerId = playerIds.get(index);
try {
final PlayerData offlinePlayerData = new PlayerData(new MMOPlayerData(playerId));
MMOCore.plugin.dataProvider.getDataManager().getDataHandler().loadData(offlinePlayerData);
// Player data is loaded, now it gets saved through SQL
sqlHandler.saveData(offlinePlayerData, false);
} catch (RuntimeException exception) {
errorCount++;
exception.printStackTrace();
}
}
batchCounter++;
}
}.runTaskTimerAsynchronously(MMOCore.plugin, 0, BATCH_PERIOD);
return CommandResult.SUCCESS;
}
}

View File

@ -1,33 +1,29 @@
package net.Indyuce.mmocore.command.rpg.admin;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.command.api.CommandVerbose;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import net.Indyuce.mmocore.command.api.CommandVerbose;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
public class ResetCommandTreeNode extends CommandTreeNode {
public ResetCommandTreeNode(CommandTreeNode parent) {
super(parent, "reset");
addChild(new ResetClassesCommandTreeNode(this));
addChild(new ResetLevelsCommandTreeNode(this));
addChild(new ResetSkillsCommandTreeNode(this));
addChild(new ResetQuestsCommandTreeNode(this));
addChild(new ResetAllCommandTreeNode(this));
addChild(new ResetAttributesCommandTreeNode(this));
addChild(new ResetWaypointsCommandTreeNode(this));
addChild(new ResetSkillTreesCommandTreeNode(this));
addChild(new ResetAllCommandTreeNode(this));
}
@Override
@ -44,7 +40,8 @@ public class ResetCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -52,25 +49,34 @@ public class ResetCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
final boolean givePoints = args.length > 4 && args[4].equalsIgnoreCase("-reallocate");
PlayerData data = PlayerData.get(player);
ResetClassesCommandTreeNode.resetClasses(data);
ResetLevelsCommandTreeNode.resetLevels(data);
ResetSkillsCommandTreeNode.resetSkills(data);
ResetQuestsCommandTreeNode.resetQuests(data);
ResetAttributesCommandTreeNode.resetAttributes(data, givePoints);
ResetWaypointsCommandTreeNode.resetWaypoints(data);
ResetSkillTreesCommandTreeNode.resetSkillTrees(data);
// Reset times-claimed not being properly emptied otherwise
data.getItemClaims().clear();
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s data was successfully reset.");
MMOCore.plugin.dataProvider.getDataManager().getDefaultData().apply(data);
data.setExperience(0);
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
data.getCollectionSkills().setExperience(profession, 0);
data.getCollectionSkills().setLevel(profession, 0);
}
MMOCore.plugin.classManager.getAll().forEach(data::unloadClassInfo);
data.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
data.mapSkillLevels().forEach((skill, level) -> data.resetSkillLevel(skill));
data.setSkillTreePoints("global", 0);
for (SkillTree skillTree : data.getProfess().getSkillTrees()) {
data.resetSkillTree(skillTree);
data.setSkillTreePoints(skillTree.getId(), 0);
}
data.resetTimesClaimed();
for(int slot:data.mapBoundSkills().keySet())
data.unbindSkill(slot);
data.getQuestData().resetFinishedQuests();
data.getQuestData().start(null);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s data was succesfully reset.");
return CommandResult.SUCCESS;
}
}
}
class ResetWaypointsCommandTreeNode extends CommandTreeNode {
public static class ResetWaypointsCommandTreeNode extends CommandTreeNode {
public ResetWaypointsCommandTreeNode(CommandTreeNode parent) {
super(parent, "waypoints");
@ -79,7 +85,8 @@ class ResetWaypointsCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -87,17 +94,13 @@ class ResetWaypointsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
resetWaypoints(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s waypoints were successfully reset.");
PlayerData data = PlayerData.get(player);
data.getWaypoints().clear();
return CommandResult.SUCCESS;
}
static void resetWaypoints(@NotNull PlayerData playerData) {
playerData.getWaypoints().clear();
}
}
class ResetQuestsCommandTreeNode extends CommandTreeNode {
public static class ResetQuestsCommandTreeNode extends CommandTreeNode {
public ResetQuestsCommandTreeNode(CommandTreeNode parent) {
super(parent, "quests");
@ -106,7 +109,8 @@ class ResetQuestsCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -114,18 +118,14 @@ class ResetQuestsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
resetQuests(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s quests were successfully reset.");
return CommandResult.SUCCESS;
}
static void resetQuests(@NotNull PlayerData data) {
PlayerData data = PlayerData.get(player);
data.getQuestData().resetFinishedQuests();
data.getQuestData().start(null);
return CommandResult.SUCCESS;
}
}
class ResetSkillsCommandTreeNode extends CommandTreeNode {
public static class ResetSkillsCommandTreeNode extends CommandTreeNode {
public ResetSkillsCommandTreeNode(CommandTreeNode parent) {
super(parent, "skills");
@ -134,7 +134,8 @@ class ResetSkillsCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -142,19 +143,18 @@ class ResetSkillsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
resetSkills(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill data was successfully reset.");
PlayerData data = PlayerData.get(player);
data.mapSkillLevels().forEach((skill, level) -> data.resetSkillLevel(skill));
while (data.hasSkillBound(0))
data.unbindSkill(0);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill data was succesfully reset.");
return CommandResult.SUCCESS;
}
static void resetSkills(@NotNull PlayerData data) {
data.mapSkillLevels().forEach((skill, ignored) -> data.resetSkillLevel(skill));
while (data.hasSkillBound(0)) data.unbindSkill(0);
data.setUnlockedItems(new HashSet<>()); // TODO class-specific unlockables etc.
}
}
class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
public static class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
public ResetSkillTreesCommandTreeNode(CommandTreeNode parent) {
super(parent, "skill-trees");
@ -163,7 +163,8 @@ class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -171,18 +172,16 @@ class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
resetSkillTrees(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill-tree data was successfully reset.");
PlayerData data = PlayerData.get(player);
for (SkillTree skillTree : data.getProfess().getSkillTrees())
data.resetSkillTree(skillTree);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill-tree data was succesfully reset.");
return CommandResult.SUCCESS;
}
// TODO option to reallocate skill tree points instead of not giving any back
static void resetSkillTrees(@NotNull PlayerData data) {
data.resetSkillTrees();
}
}
class ResetAttributesCommandTreeNode extends CommandTreeNode {
public class ResetAttributesCommandTreeNode extends CommandTreeNode {
public ResetAttributesCommandTreeNode(CommandTreeNode parent) {
super(parent, "attributes");
@ -192,7 +191,8 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -200,16 +200,12 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
final boolean givePoints = args.length > 4 && args[4].equalsIgnoreCase("-reallocate");
resetAttributes(PlayerData.get(player), givePoints);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s attributes were successfully reset.");
return CommandResult.SUCCESS;
}
PlayerData data = PlayerData.get(player);
static void resetAttributes(@NotNull PlayerData data, boolean givePoints) {
// Give back attribute points
if (givePoints) {
/*
* force reallocating of player attribute points
*/
if (args.length > 4 && args[4].equalsIgnoreCase("-reallocate")) {
int points = 0;
for (PlayerAttributes.AttributeInstance ins : data.getAttributes().getInstances()) {
@ -218,17 +214,19 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
}
data.giveAttributePoints(points);
return;
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s attribute points spendings were successfully reset.");
return CommandResult.SUCCESS;
}
for (PlayerAttribute attribute : MMOCore.plugin.attributeManager.getAll()) {
attribute.resetAdvancement(data, true);
data.getAttributes().getInstance(attribute).setBase(0);
}
data.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s attributes were succesfully reset.");
return CommandResult.SUCCESS;
}
}
class ResetLevelsCommandTreeNode extends CommandTreeNode {
public static class ResetLevelsCommandTreeNode extends CommandTreeNode {
public ResetLevelsCommandTreeNode(CommandTreeNode parent) {
super(parent, "levels");
@ -237,7 +235,8 @@ class ResetLevelsCommandTreeNode extends CommandTreeNode {
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
if (args.length < 4)
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
@ -245,52 +244,19 @@ class ResetLevelsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
resetLevels(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s levels were successfully reset.");
return CommandResult.SUCCESS;
}
static void resetLevels(@NotNull PlayerData data) {
// Class
data.setLevel(MMOCore.plugin.playerDataManager.getDefaultData().getLevel());
PlayerData data = PlayerData.get(player);
data.setLevel(MMOCore.plugin.dataProvider.getDataManager().getDefaultData().getLevel());
data.setExperience(0);
data.getProfess().resetAdvancement(data, true);
// Professions
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
data.getCollectionSkills().setExperience(profession, 0);
data.getCollectionSkills().setLevel(profession, 0);
profession.resetAdvancement(data, true);
}
}
profession.getExperienceTable().reset(data, profession);
}
class ResetClassesCommandTreeNode extends CommandTreeNode {
public ResetClassesCommandTreeNode(CommandTreeNode parent) {
super(parent, "classes");
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s levels were succesfully reset.");
addParameter(Parameter.PLAYER);
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4) return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
return CommandResult.FAILURE;
}
resetClasses(PlayerData.get(player));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s classes were successfully reset.");
return CommandResult.SUCCESS;
}
static void resetClasses(@NotNull PlayerData data) {
MMOCore.plugin.classManager.getAll().forEach(data::unloadClassInfo);
MMOCore.plugin.playerDataManager.getDefaultData().apply(data);
data.setClass(MMOCore.plugin.classManager.getDefaultClass());
}
}

View File

@ -30,7 +30,7 @@ public class SaveDataTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
MMOCore.plugin.playerDataManager.getDataHandler().saveData(PlayerData.get(player), false);
MMOCore.plugin.dataProvider.getDataManager().getDataHandler().saveData(PlayerData.get(player), false);
return CommandResult.SUCCESS;
}

View File

@ -68,6 +68,7 @@ public class SkillCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
int amount;
try {
amount = Integer.parseInt(args[5]);
@ -77,7 +78,7 @@ public class SkillCommandTreeNode extends CommandTreeNode {
}
int value = change.apply(playerData.getSkillLevel(skill), amount);
playerData.setSkillLevel(skill, value);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + player.getName() + ChatColor.YELLOW
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + player.getName() + ChatColor.YELLOW
+ " is now level " + ChatColor.GOLD + value + ChatColor.YELLOW + " for " + skill.getName() + ".");
return CommandResult.SUCCESS;
}
@ -100,31 +101,31 @@ public class SkillCommandTreeNode extends CommandTreeNode {
return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
sender.sendMessage(ChatColor.RED + "Could not find player called " + args[3] + ".");
sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
return CommandResult.FAILURE;
}
PlayerData playerData = PlayerData.get(player);
ClassSkill skill = playerData.getProfess().getSkill(args[4]);
if (skill == null) {
sender.sendMessage(ChatColor.RED + "Class doesn't have a skill called " + args[4] + ".");
sender.sendMessage(ChatColor.RED + "The player's class doesn't have a skill called " + args[4] + ".");
return CommandResult.FAILURE;
}
if (lock) {
if (!playerData.hasUnlocked(skill)) {
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "Skill " + skill.getSkill().getName() + " already locked for " + player.getName());
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill " + skill.getSkill().getName() + " is already locked" + " for " + player.getName());
return CommandResult.SUCCESS;
}
playerData.lock(skill);
} else {
if (playerData.hasUnlocked(skill)) {
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "Skill " + skill.getSkill().getName() + " already unlocked for " + player.getName());
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill " + skill.getSkill().getName() + " is already unlocked" + " for " + player.getName());
return CommandResult.SUCCESS;
}
playerData.unlock(skill);
}
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + "Skill " + ChatColor.GOLD + skill.getSkill().getName() + ChatColor.YELLOW + " now " + (lock ? "locked" : "unlocked") + " for " + ChatColor.GOLD + player.getName());
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill.getSkill().getName() + " is now " + (lock ? "locked" : "unlocked" + " for " + player.getName()));
return CommandResult.SUCCESS;
}
}

View File

@ -4,7 +4,6 @@ import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.skill.binding.BoundSkillInfo;
import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.command.api.CommandVerbose;
import net.Indyuce.mmocore.skill.ClassSkill;
@ -54,6 +53,10 @@ public class SlotCommandTreeNode extends CommandTreeNode {
sender.sendMessage(ChatColor.RED + "The slot can't be negative.");
return CommandResult.FAILURE;
}
if (slot > MMOCore.plugin.configManager.maxSkillSlots) {
sender.sendMessage(ChatColor.RED + "The slot can't be higher than " + MMOCore.plugin.configManager.maxSkillSlots + ".");
return CommandResult.FAILURE;
}
SkillSlot skillSlot = playerData.getProfess().getSkillSlot(slot);
if(skillSlot.isUnlockedByDefault()){
sender.sendMessage(ChatColor.RED + "You can't lock a skill that is unlocked by default.");
@ -73,7 +76,7 @@ public class SlotCommandTreeNode extends CommandTreeNode {
}
playerData.unlock(skillSlot);
}
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + "The skill slot " + skillSlot.getName() + " is now " + (lock ? "locked" : "unlocked" + " for " + player.getName()));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill slot " + skillSlot.getName() + " is now " + (lock ? "locked" : "unlocked" + " for " + player.getName()));
return CommandResult.SUCCESS;
}
}
@ -114,7 +117,7 @@ public class SlotCommandTreeNode extends CommandTreeNode {
}
playerData.bindSkill(slot, skill);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + "Skill " + ChatColor.GOLD + skill.getSkill().getHandler().getId() + ChatColor.YELLOW + " now bound to slot " + ChatColor.GOLD + slot);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill.getSkill().getHandler().getId() + " is now bound to the slot " + slot);
return CommandResult.SUCCESS;
}
}
@ -144,10 +147,11 @@ public class SlotCommandTreeNode extends CommandTreeNode {
sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number.");
return CommandResult.FAILURE;
}
final BoundSkillInfo found = playerData.unbindSkill(slot);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + (found != null ?
"Skill " + ChatColor.GOLD + found.getClassSkill().getSkill().getName() + ChatColor.YELLOW + " was taken off the slot " + ChatColor.GOLD + slot :
"Could not find skill at slot " + ChatColor.GOLD + slot));
String skill = playerData.hasSkillBound(slot) ? playerData.getBoundSkill(slot).getSkill().getHandler().getId() : "none";
if (playerData.hasSkillBound(slot))
playerData.unbindSkill(slot);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill + " has been unbounded from the slot " + slot);
return CommandResult.SUCCESS;
}
}

View File

@ -49,7 +49,7 @@ public class CreateCommandTreeNode extends CommandTreeNode {
if (args[2].equalsIgnoreCase("main")) {
MMOCore.plugin.boosterManager.register(new Booster(args.length > 5 ? args[5] : null, extra, length));
ConfigMessage.fromKey("booster-main").addPlaceholders("multiplier", "" + (1 + extra)).send(Bukkit.getOnlinePlayers());
new ConfigMessage("booster-main").addPlaceholders("multiplier", "" + (1 + extra)).send(Bukkit.getOnlinePlayers());
Bukkit.getOnlinePlayers().forEach(player -> player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1));
return CommandResult.SUCCESS;
}
@ -62,7 +62,7 @@ public class CreateCommandTreeNode extends CommandTreeNode {
Profession profession = MMOCore.plugin.professionManager.get(format);
MMOCore.plugin.boosterManager.register(new Booster(args.length > 5 ? args[5] : null, profession, extra, length));
ConfigMessage.fromKey("booster-skill").addPlaceholders("multiplier", "" + (1 + extra), "profession", profession.getName())
new ConfigMessage("booster-skill").addPlaceholders("multiplier", "" + (1 + extra), "profession", profession.getName())
.send(Bukkit.getOnlinePlayers());
Bukkit.getOnlinePlayers().forEach(player -> player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1));
return CommandResult.SUCCESS;

View File

@ -33,7 +33,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode {
sender.sendMessage("Stat Modifiers (" + instance.getKeys().size() + "):");
for (String key : instance.getKeys()) {
StatModifier mod = instance.getModifier(key);
sender.sendMessage("-> '" + key + "' " + mod.getValue() + " " + mod.getType().name() + " " + mod.getSlot() + " " + mod.getSource());
sender.sendMessage("- " + key + ": " + mod.getValue() + " " + mod.getType().name());
}
return CommandResult.SUCCESS;

View File

@ -28,7 +28,7 @@ public class OpenCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE;
}
InventoryManager.WAYPOINTS.newInventory(PlayerData.get(player)).open();
InventoryManager.WAYPOINTS.generate(PlayerData.get(player), null).open();
return CommandResult.SUCCESS;
}
}

View File

@ -4,7 +4,7 @@ import io.lumine.mythic.api.adapters.AbstractItemStack;
import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.drops.DropMetadata;
import io.lumine.mythic.api.drops.IItemDrop;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.adapters.BukkitItemStack;
import io.lumine.mythic.core.drops.Drop;
import net.Indyuce.mmocore.util.item.CurrencyItemBuilder;
@ -27,8 +27,7 @@ public class CurrencyItemDrop extends Drop implements IItemDrop {
@Override
public AbstractItemStack getDrop(DropMetadata dropMetadata, double v) {
// Not great wrt to performance. Should build the item like MM does
return BukkitAdapter.adapt(new CurrencyItemBuilder(key, random(minw, maxw)).build());
return new BukkitItemStack(new CurrencyItemBuilder(key, random(minw, maxw)).build());
}
private int random(int a, int b) {

View File

@ -4,7 +4,7 @@ import io.lumine.mythic.api.adapters.AbstractItemStack;
import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.drops.DropMetadata;
import io.lumine.mythic.api.drops.IItemDrop;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.adapters.BukkitItemStack;
import io.lumine.mythic.core.drops.Drop;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
@ -49,8 +49,7 @@ public class GoldPouchDrop extends Drop implements IItemDrop {
}
nbt.addTag(new ItemTag("RpgPouchSize", 18), new ItemTag("RpgPouchMob", true), new ItemTag("RpgPouchInventory", MMOCoreUtils.toBase64(content)));
// Not great wrt to performance. Should build the item like MM does
return BukkitAdapter.adapt(nbt.toItem());
return new BukkitItemStack(nbt.toItem());
}
private ItemStack setAmount(ItemStack item, int amount) {

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.comp.placeholder;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import org.bukkit.OfflinePlayer;
import io.lumine.mythic.lib.MythicLib;
@ -8,9 +7,7 @@ import io.lumine.mythic.lib.MythicLib;
public class DefaultParser implements PlaceholderParser {
@Override
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
public String parse(OfflinePlayer player, String string) {
// TODO remove use of confusing non-PAPI %player% placeholder
return MythicLib.plugin.parseColors(string.replace("%player%", player.getName()));
}
}

View File

@ -12,10 +12,8 @@ import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.skill.CastableSkill;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
@ -60,11 +58,10 @@ public class RPGPlaceholders extends PlaceholderExpansion {
public String onRequest(OfflinePlayer player, String identifier) {
if (!PlayerData.has(player.getUniqueId()))
return null;
final PlayerData playerData = PlayerData.get(player);
PlayerData playerData = PlayerData.get(player);
if (identifier.equals("mana_icon"))
return playerData.getProfess().getManaDisplay().getIcon();
if (identifier.equals("mana_name"))
return playerData.getProfess().getManaDisplay().getName();
@ -73,49 +70,24 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.startsWith("skill_level_")) {
String id = identifier.substring(12);
RegisteredSkill skill = MMOCore.plugin.skillManager.getSkillOrThrow(id);
RegisteredSkill skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(id), "Could not find skill with ID '" + id + "'");
return String.valueOf(playerData.getSkillLevel(skill));
}
/*
* Given a skill slot number (integer) and a parameter name,
* return the player's value of that skill parameter from that
* specific skill slot.
*/
else if (identifier.startsWith("bound_skill_parameter_")) {
final String[] ids = identifier.substring(22).split(":");
final String parameterId = ids[0];
final int skillSlot = Integer.parseInt(ids[1]);
final ClassSkill found = playerData.getBoundSkill(skillSlot);
if (found == null) return "";
final CastableSkill castable = found.toCastable(playerData);
final double value = playerData.getMMOPlayerData().getSkillModifierMap().calculateValue(castable, parameterId);
} else if (identifier.startsWith("skill_modifier_") || identifier.startsWith("skill_parameter_")) {
String[] ids = (identifier.startsWith("skill_modifier_") ? identifier.substring(15) : identifier.substring(16)).split(":");
String parameterId = ids[0];
String skillId = ids[1];
RegisteredSkill skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(skillId), "Could not find skill with ID '" + skillId + "'");
ClassSkill classSkill = playerData.getProfess().getSkill(skill);
double value = classSkill.toCastable(playerData).getParameter(parameterId);
return MythicLib.plugin.getMMOConfig().decimal.format(value);
}
// Returns a player's value of a skill parameter.
else if (identifier.startsWith("skill_modifier_") || identifier.startsWith("skill_parameter_")) {
final String[] ids = identifier.substring(identifier.startsWith("skill_modifier_") ? 15 : 16).split(":");
final String parameterId = ids[0];
final String skillId = ids[1];
final RegisteredSkill skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(skillId), "Could not find skill with ID '" + skillId + "'");
final CastableSkill castable = playerData.getProfess().getSkill(skill).toCastable(playerData);
final double value = playerData.getMMOPlayerData().getSkillModifierMap().calculateValue(castable, parameterId);
return MythicLib.plugin.getMMOConfig().decimal.format(value);
}
else if (identifier.startsWith("attribute_points_spent_")) {
final String attributeId = identifier.substring(23);
final PlayerAttributes.AttributeInstance attributeInstance = Objects.requireNonNull(playerData.getAttributes().getInstance(attributeId), "Could not find attribute with ID '" + attributeId + "'");
return String.valueOf(attributeInstance.getBase());
}
else if (identifier.equals("level_percent")) {
} else if (identifier.startsWith("attribute_points_spent_")) {
String attributeId = identifier.substring(31);
PlayerAttributes.AttributeInstance attributeInstance = Objects.requireNonNull(playerData.getAttributes().getInstance(attributeId), "Could not find attribute with ID '" + attributeId + "'");
return String.valueOf(attributeInstance.getSpent());
} else if (identifier.equals("level_percent")) {
double current = playerData.getExperience(), next = playerData.getLevelUpExperience();
return MythicLib.plugin.getMMOConfig().decimal.format(current / next * 100);
}
else if (identifier.equals("health"))
} else if (identifier.equals("health"))
return StatManager.format("MAX_HEALTH", player.getPlayer().getHealth());
else if (identifier.equals("max_health"))
@ -155,42 +127,19 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.startsWith("since_last_hit"))
return playerData.isInCombat() ? MythicLib.plugin.getMMOConfig().decimal.format((System.currentTimeMillis() - playerData.getCombat().getLastHit()) / 1000.) : "-1";
// Returns the bound skill ID
else if (identifier.startsWith("id_bound_")) {
final int slot = Math.max(1, Integer.parseInt(identifier.substring(9)));
final ClassSkill info = playerData.getBoundSkill(slot);
return info == null ? "" : info.getSkill().getHandler().getId();
}
// Returns the casting slot taking into account the skill slot offset
else if (identifier.startsWith("cast_slot_offset_")) {
final Player online = player.getPlayer();
Validate.notNull(online, "Player is offline");
final int slot = Integer.parseInt(identifier.substring(17));
return String.valueOf(slot + (online.getInventory().getHeldItemSlot() < slot ? 1 : 0));
}
// Is there a passive skill bound to given slot
else if (identifier.startsWith("passive_bound_")) {
final int slot = Integer.parseInt(identifier.substring(14));
final ClassSkill skill = playerData.getBoundSkill(slot);
return String.valueOf(skill != null && skill.getSkill().getTrigger().isPassive());
}
// Returns the bound skill name
else if (identifier.startsWith("bound_")) {
final int slot = Math.max(1, Integer.parseInt(identifier.substring(6)));
final ClassSkill skill = playerData.getBoundSkill(slot);
if (skill == null) return MMOCore.plugin.configManager.noSkillBoundPlaceholder;
int slot = Math.max(0, Integer.parseInt(identifier.substring(6)));
if (playerData.hasSkillBound(slot)) {
ClassSkill skill = playerData.getBoundSkill(slot);
return (playerData.getCooldownMap().isOnCooldown(skill) ? ChatColor.RED : ChatColor.GREEN) + skill.getSkill().getName();
}
// Returns cooldown of skill bound at given slot
else if (identifier.startsWith("cooldown_bound_")) {
} else
return MMOCore.plugin.configManager.noSkillBoundPlaceholder;
} else if (identifier.startsWith("cooldown_bound_")) {
int slot = Math.max(0, Integer.parseInt(identifier.substring(15)));
if (playerData.hasSkillBound(slot))
return Double.toString(playerData.getCooldownMap().getCooldown(playerData.getBoundSkill(slot)));
else return MMOCore.plugin.configManager.noSkillBoundPlaceholder;
return "" + playerData.getCooldownMap().getCooldown(playerData.getBoundSkill(slot));
else
return MMOCore.plugin.configManager.noSkillBoundPlaceholder;
} else if (identifier.startsWith("profession_experience_"))
return MythicLib.plugin.getMMOConfig().decimal.format(
playerData.getCollectionSkills().getExperience(identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase()));

View File

@ -15,9 +15,10 @@ import net.Indyuce.mmocore.manager.InventoryManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
public class ForceClassProfileDataModule implements ProfileDataModule {
public class ForceClassProfileDataModule implements ProfileDataModule, Listener {
public ForceClassProfileDataModule() {
final ProfileProvider<?> provider = Bukkit.getServicesManager().getRegistration(ProfileProvider.class).getProvider();
provider.registerModule(this);
@ -46,7 +47,7 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
}
final PlayerData playerData = PlayerData.get(event.getPlayerData().getPlayer());
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open();
InventoryManager.CLASS_SELECT.generate(playerData, () -> event.validate(this), null).open();
}
/**
@ -61,8 +62,7 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
if (!event.hasProfileEvent()) {
Validate.isTrue(MythicLib.plugin.getProfileMode() == ProfileMode.PROXY, "Listened to a data load event with no profile event attached but proxy-based profiles are disabled");
if (playerData.getProfess().equals(MMOCore.plugin.classManager.getDefaultClass()))
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> {
}).open();
InventoryManager.CLASS_SELECT.generate(playerData, null).open();
return;
}
@ -70,7 +70,7 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
// Validate if necessary
if (playerData.getProfess().equals(MMOCore.plugin.classManager.getDefaultClass()))
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event1.validate(this)).open();
InventoryManager.CLASS_SELECT.generate(playerData, () -> event1.validate(this), null).open();
else event1.validate(this);
}
}

View File

@ -3,7 +3,6 @@ package net.Indyuce.mmocore.comp.profile;
import fr.phoenixdevt.profiles.ProfileDataModule;
import fr.phoenixdevt.profiles.event.ProfileCreateEvent;
import fr.phoenixdevt.profiles.event.ProfileRemoveEvent;
import fr.phoenixdevt.profiles.placeholder.PlaceholderProcessor;
import fr.phoenixdevt.profiles.placeholder.PlaceholderRequest;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
@ -12,9 +11,10 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.experience.Profession;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
public class MMOCoreProfileDataModule implements ProfileDataModule, PlaceholderProcessor {
public class MMOCoreProfileDataModule implements ProfileDataModule, Listener {
@Override
public JavaPlugin getOwningPlugin() {
@ -22,13 +22,13 @@ public class MMOCoreProfileDataModule implements ProfileDataModule, PlaceholderP
}
@Override
public String getIdentifier() {
return "mmocore";
public boolean hasPlaceholders() {
return true;
}
@Override
public ProfileDataModule getDataModule() {
return this;
public String getIdentifier() {
return "mmocore";
}
@Override

View File

@ -10,7 +10,6 @@ import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
public class PvPFlagHandler extends MMOCoreFlagHandler {
@ -51,7 +50,7 @@ public class PvPFlagHandler extends MMOCoreFlagHandler {
// Send message
if (canSendMessage()) {
lastMessage = System.currentTimeMillis();
ConfigMessage.fromKey("pvp-mode.enter.pvp-mode-on", "time",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.enter.pvp-mode-on", "time",
MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange)).send(playerData.getPlayer());
}
}

View File

@ -12,7 +12,6 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import io.lumine.mythic.lib.comp.flags.WorldGuardFlags;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.command.PvpModeCommand;
import java.util.Objects;
@ -65,7 +64,7 @@ public class PvPModeHandler extends MMOCoreFlagHandler {
final boolean pvpEnabled = playerData.getCombat().isInPvpMode() && !playerData.getCombat().canQuitPvpMode() && pvpFlag;
lastMessage = System.currentTimeMillis();
final double remaining = (playerData.getCombat().getLastHit() + MMOCore.plugin.configManager.pvpModeCombatTimeout * 1000.0D - System.currentTimeMillis()) / 1000.0D;
ConfigMessage.fromKey("pvp-mode.leave.pvp-" + (pvpEnabled ? "allowed" : "denied"), "remaining",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.leave.pvp-" + (pvpEnabled ? "allowed" : "denied"), "remaining",
(MythicLib.plugin.getMMOConfig()).decimal.format(remaining)).send(playerData.getPlayer());
}
} else if (newPvpMode && !lastPvpMode) {
@ -81,7 +80,7 @@ public class PvPModeHandler extends MMOCoreFlagHandler {
// Send message
if (canSendMessage()) {
lastMessage = System.currentTimeMillis();
ConfigMessage.fromKey("pvp-mode.enter.pvp-mode-" + (applyInvulnerability ? "on" : "off"), "time",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.enter.pvp-mode-" + (applyInvulnerability ? "on" : "off"), "time",
MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange)).send(playerData.getPlayer());
}
}

View File

@ -6,7 +6,6 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
@ -54,14 +53,14 @@ public class PvPModeListener implements Listener {
if (targetData.getLevel() < minLevel) {
event.setCancelled(true);
if (event.getDamage() > 0)
ConfigMessage.fromKey("pvp-mode.cannot-hit.low-level-target").send(source);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.low-level-target").send(source);
return;
}
if (sourceData.getLevel() < minLevel) {
event.setCancelled(true);
if (event.getDamage() > 0)
ConfigMessage.fromKey("pvp-mode.cannot-hit.low-level-self").send(source);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.low-level-self").send(source);
return;
}
@ -69,7 +68,7 @@ public class PvPModeListener implements Listener {
if (maxLevelDiff > 0 && Math.abs(targetData. getLevel() - sourceData.getLevel()) > maxLevelDiff) {
event.setCancelled(true);
if (event.getDamage() > 0)
ConfigMessage.fromKey("pvp-mode.cannot-hit.high-level-difference").send(source);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.high-level-difference").send(source);
return;
}
}
@ -81,7 +80,7 @@ public class PvPModeListener implements Listener {
if (targetData.getCombat().isInvulnerable()) {
if (event.getDamage() > 0) {
final long left = targetData.getCombat().getInvulnerableTill() - System.currentTimeMillis();
ConfigMessage.fromKey("pvp-mode.cannot-hit.invulnerable-target",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.invulnerable-target",
"left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source);
}
event.setCancelled(true);
@ -92,7 +91,7 @@ public class PvPModeListener implements Listener {
if (!MMOCore.plugin.configManager.pvpModeInvulnerabilityCanDamage && sourceData.getCombat().isInvulnerable()) {
if (event.getDamage() > 0) {
final long left = sourceData.getCombat().getInvulnerableTill() - System.currentTimeMillis();
ConfigMessage.fromKey("pvp-mode.cannot-hit.invulnerable-self",
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.invulnerable-self",
"left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source);
}
event.setCancelled(true);
@ -109,14 +108,14 @@ public class PvPModeListener implements Listener {
if (!targetData.getCombat().isInPvpMode()) {
event.setCancelled(true);
if (event.getDamage() > 0)
ConfigMessage.fromKey("pvp-mode.cannot-hit.pvp-mode-disabled-target").send(source);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.pvp-mode-disabled-target").send(source);
}
// Attacker has not enabled PvP mode
else if (!sourceData.getCombat().isInPvpMode()) {
event.setCancelled(true);
if (event.getDamage() > 0)
ConfigMessage.fromKey("pvp-mode.cannot-hit.pvp-mode-disabled-self").send(source);
MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.pvp-mode-disabled-self").send(source);
}
}
}

View File

@ -35,10 +35,9 @@ public class ExpCurve {
* @param file Text file to read data from
* @throws IOException IO exception when reading file
*/
public ExpCurve(File file) {
public ExpCurve(File file) throws IOException {
this.id = file.getName().replace(".txt", "").toLowerCase().replace("_", "-").replace(" ", "-");
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String readLine;
while ((readLine = reader.readLine()) != null)
@ -46,9 +45,6 @@ public class ExpCurve {
reader.close();
Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve");
} catch(Throwable throwable) {
throw new RuntimeException(throwable);
}
}
/**

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import org.jetbrains.annotations.NotNull;
@ -11,8 +10,7 @@ import javax.annotation.Nullable;
* General implementation for professions, classes and attributes.
* <p>
* An experience object is a type of object that can level up.
* It has an experience curve and table and can receive EXP. It
* is what most resembles the Mythic abstraction of "archetypes".
* It has an experience curve and table and can receive EXP
*
* @author jules
*/
@ -38,17 +36,4 @@ public interface ExperienceObject extends ExperienceDispenser {
ExperienceTable getExperienceTable();
boolean hasExperienceTable();
/**
* Resets the advancement of an archetype for a player. This only
* applies to the object's experience table though, and does not
* actually decrease class level/profession level & exp bar.
*/
public default void resetAdvancement(@NotNull PlayerData playerData, boolean levels) {
if (hasExperienceTable()) getExperienceTable().unclaim(playerData, this, levels);
}
public default void updateAdvancement(@NotNull PlayerData playerData, int newLevel) {
if (hasExperienceTable()) getExperienceTable().claim(playerData, newLevel, this);
}
}

View File

@ -0,0 +1,21 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
/**
* Professions and classes share the same properties because
* they have both exp curves and tables.
* <p>
* A 'claimer' is an object that can claim exp tables and therefore
* needs to save how many times it has already claimed some item
* before.
* <p>
* Since MMOCore 1.9 it's all centralized in the player class data
*/
public interface ExperienceTableClaimer {
int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item);
void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int claims);
}

View File

@ -1,10 +1,10 @@
package net.Indyuce.mmocore.experience;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.gson.JsonElement;
import io.lumine.mythic.lib.gson.JsonObject;
import io.lumine.mythic.lib.version.VParticle;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent;
@ -18,6 +18,7 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
@ -85,7 +86,7 @@ public class PlayerProfessions {
* When loading data through SQL
*/
public void load(String json) {
JsonObject obj = MythicLib.plugin.getGson().fromJson(json, JsonObject.class);
JsonObject obj = new Gson().fromJson(json, JsonObject.class);
// Load profession exp and levels
for (Entry<String, JsonElement> entry : obj.entrySet())
@ -154,11 +155,11 @@ public class PlayerProfessions {
return profession.hasMaxLevel() && getLevel(profession) >= profession.getMaxLevel();
}
public void giveExperience(@NotNull Profession profession, double value, @NotNull EXPSource source) {
public void giveExperience(Profession profession, double value, EXPSource source) {
giveExperience(profession, value, source, null, true);
}
public void giveExperience(@NotNull Profession profession, double value, @NotNull EXPSource source, @Nullable Location hologramLocation, boolean splitExp) {
public void giveExperience(Profession profession, double value, EXPSource source, @Nullable Location hologramLocation, boolean splitExp) {
Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player");
if (value <= 0) {
exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0d) + value));
@ -189,8 +190,8 @@ public class PlayerProfessions {
return;
// Display hologram
if (hologramLocation != null && profession.getOption(Profession.ProfessionOption.EXP_HOLOGRAMS))
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), ConfigMessage.fromKey("exp-hologram", "exp", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience())).asLine());
if (hologramLocation != null)
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience())).message());
exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0d) + event.getExperience()));
int level, oldLevel = getLevel(profession);
@ -214,24 +215,25 @@ public class PlayerProfessions {
playerData.giveExperience(profession.getExperience().calculate(level), null);
// Apply profession experience table
profession.updateAdvancement(playerData, level);
if (profession.hasExperienceTable())
profession.getExperienceTable().claim(playerData, level, profession);
}
if (check) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
new SmallParticleEffect(playerData.getPlayer(), VParticle.INSTANT_EFFECT.get());
ConfigMessage.fromKey("profession-level-up").addPlaceholders("level", String.valueOf(level), "profession", profession.getName())
new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
new ConfigMessage("profession-level-up").addPlaceholders("level", String.valueOf(level), "profession", profession.getName())
.send(playerData.getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(playerData.getPlayer());
playerData.getStats().updateStats();
}
StringBuilder bar = new StringBuilder(ChatColor.BOLD.toString());
StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
int chars = (int) (exp / needed * 20);
for (int j = 0; j < 20; j++)
bar.append(j == chars ? ChatColor.WHITE.toString() + ChatColor.BOLD : "").append("|");
bar.append(j == chars ? "" + ChatColor.WHITE + ChatColor.BOLD : "").append("|");
if (playerData.isOnline())
ConfigMessage.fromKey("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio",
MMOCore.plugin.configManager.getSimpleMessage("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio",
MythicLib.plugin.getMMOConfig().decimal.format(exp / needed * 100)).send(playerData.getPlayer());
}
}

View File

@ -1,8 +1,7 @@
package net.Indyuce.mmocore.experience;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.util.PostLoadAction;
import io.lumine.mythic.lib.util.PreloadedObject;
import io.lumine.mythic.lib.api.util.PostLoadObject;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
@ -19,7 +18,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
public class Profession implements ExperienceObject, PreloadedObject {
public class Profession extends PostLoadObject implements ExperienceObject {
private final String id, name;
private final int maxLevel;
private final Map<ProfessionOption, Boolean> options = new HashMap<>();
@ -32,14 +31,8 @@ public class Profession implements ExperienceObject, PreloadedObject {
*/
private final LinearValue experience;
private final PostLoadAction postLoadAction = new PostLoadAction(config -> {
// Link profession to hardcoded profession manager
MMOCore.plugin.professionManager.loadProfessionConfigurations(this, config);
});
public Profession(String id, ConfigurationSection config) {
postLoadAction.cacheConfig(config);
public Profession(String id, FileConfiguration config) {
super(config);
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
this.name = config.getString("name");
@ -81,10 +74,9 @@ public class Profession implements ExperienceObject, PreloadedObject {
}
}
@NotNull
@Override
public PostLoadAction getPostLoadAction() {
return postLoadAction;
protected void whenPostLoaded(ConfigurationSection configurationSection) {
MMOCore.plugin.professionManager.loadProfessionConfigurations(this, configurationSection);
}
public boolean getOption(ProfessionOption option) {
@ -132,7 +124,8 @@ public class Profession implements ExperienceObject, PreloadedObject {
}
@Override
public void giveExperience(@NotNull PlayerData playerData, double experience, @Nullable Location hologramLocation, @NotNull EXPSource source) {
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, EXPSource source) {
hologramLocation = !getOption(Profession.ProfessionOption.EXP_HOLOGRAMS) ? null : hologramLocation;
playerData.getCollectionSkills().giveExperience(this, experience, EXPSource.SOURCE, hologramLocation, true);
}

View File

@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Used to differentiate between the main class experience and
* Used to differenciate between the main class experience and
* experience given in a specific profession. Also being used to
* monitor EXP holograms.
*

View File

@ -3,9 +3,9 @@ package net.Indyuce.mmocore.experience.droptable;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.StatTrigger;
import net.Indyuce.mmocore.api.quest.trigger.Trigger;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.quest.trigger.api.Temporary;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -132,11 +132,12 @@ public class ExperienceItem {
}
/**
* Used when a player logs back, in order to apply again
* all the temporary triggers.
* Used when a player connects back to give back all the stats that he should have.
*
* @param playerData
*/
public void applyTemporaryTriggers(PlayerData playerData) {
public void applyRemovableTrigger(PlayerData playerData) {
for (Trigger trigger : triggers)
if (trigger instanceof Temporary) trigger.apply(playerData);
if (trigger instanceof Removable) trigger.apply(playerData);
}
}

View File

@ -5,7 +5,6 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.ExperienceObject;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ -37,49 +36,61 @@ public class ExperienceTable {
}
/**
* Called when a player levels up something.
* Called when a player levels up one of his professions
*
* @param levelingUp Player leveling up
* @param professionLevel New profession level
* @param object The object being level up. This MUST be the parent object
* owning the calling experience table! In other words,
* <code>object.getExperienceTable() == this</code> must remain true.
* @param object Either profession or class leveling up
*/
public void claim(@NotNull PlayerData levelingUp, int professionLevel, @NotNull ExperienceObject object) {
public void claim(PlayerData levelingUp, int professionLevel, ExperienceObject object) {
for (ExperienceItem item : items) {
final int timesClaimed = levelingUp.getClaims(object, item);
if (!item.roll(professionLevel, timesClaimed)) continue;
int timesClaimed = levelingUp.getClaims(object, this, item);
if (!item.roll(professionLevel, timesClaimed))
continue;
levelingUp.setClaims(object, item, timesClaimed + 1);
levelingUp.setClaims(object, this, item, timesClaimed + 1);
item.applyTriggers(levelingUp);
}
}
public void unclaim(@NotNull PlayerData playerData, @NotNull ExperienceObject object, boolean reset) {
/**
* Called when a player changes its class.
* Removes the perm stat but keeps the item claims in memory.
*/
public void removePermStats(PlayerData playerData, ExperienceObject object) {
for (ExperienceItem item : items) {
// Undo triggers
for (int i = 0; i < playerData.getClaims(object, item); i++)
int timesClaimed = playerData.getClaims(object, this, item);
for (int i = 0; i < timesClaimed; i++)
item.removeTriggers(playerData);
// Reset levels
if (reset) playerData.setClaims(object, item, 0);
}
}
/**
* Called when a player joins. All non-permanent/temporary triggers
* must be granted back to the player, including player modifiers.
* Called when the progression is reset(e.g skill tree reallocation)
*/
public void reset(PlayerData playerData, ExperienceObject object) {
for (ExperienceItem item : items) {
int timesClaimed = playerData.getClaims(object, this, item);
playerData.setClaims(object, this, item, 0);
for (int i = 0; i < timesClaimed; i++)
item.removeTriggers(playerData);
}
}
/**
* Called when a player joins and all the removable triggers get claimed back.
*
* @param data PlayerData
* @param object Either profession, skillTreeNode or class leveling up
*/
public void applyTemporaryTriggers(@NotNull PlayerData data, @NotNull ExperienceObject object) {
public void claimRemovableTrigger(PlayerData data, ExperienceObject object) {
for (ExperienceItem item : items) {
final int timesClaimed = data.getClaims(object, item);
int timesClaimed = data.getClaims(object, this, item);
for (int i = 0; i < timesClaimed; i++)
item.applyTemporaryTriggers(data);
item.applyRemovableTrigger(data);
}
}
}

View File

@ -3,9 +3,9 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -44,12 +44,9 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
@Override
public ExperienceSourceManager<BrewPotionExperienceSource> newManager() {
return new Manager();
}
return new ExperienceSourceManager<BrewPotionExperienceSource>() {
private static class Manager extends ExperienceSourceManager<BrewPotionExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(BrewEvent event) {
Optional<Player> playerOpt = getNearbyPlayer(event.getBlock().getLocation());
if (!playerOpt.isPresent())
@ -65,9 +62,11 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
PlayerData data = PlayerData.get(playerOpt.get());
for (BrewPotionExperienceSource source : getSources())
if (source.matches(data, (PotionMeta) brewn.getItemMeta()))
new PotionUpgrade(found, brewn).process(source, data.getPlayer());
new PotionUpgrade(found, brewn).process(data.getPlayer());
});
}
};
}
private ItemStack findPotion(BrewerInventory inv) {
for (int j = 0; j < 3; j++) {
@ -81,9 +80,8 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
private Optional<Player> getNearbyPlayer(Location loc) {
return loc.getWorld().getPlayers().stream().filter(player -> player.getLocation().distanceSquared(loc) < 100).findAny();
}
}
private static class PotionUpgrade {
public class PotionUpgrade {
/*
* if the potion was extended using redstone or upgraded using
@ -163,14 +161,14 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
// effect.getType() == type).findFirst();
// }
public void process(BrewPotionExperienceSource source, Player player) {
public void process(Player player) {
/*
* calculate extra exp due to extra effects
*/
// exp += getTotal(mapEffectDurations());
source.getDispenser().giveExperience(PlayerData.get(player), exp * source.multiplier, player.getLocation(), EXPSource.SOURCE);
getDispenser().giveExperience(PlayerData.get(player), exp * multiplier, player.getLocation(), EXPSource.SOURCE);
}
}
}

View File

@ -11,6 +11,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerMoveEvent;
import static org.bukkit.event.EventPriority.HIGHEST;
import static org.bukkit.event.EventPriority.MONITOR;
public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
//Can be Ladder,Vines,Twisting Vines,Weeping Vines.
@ -35,28 +36,14 @@ public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
type = Material.valueOf(str);
}
}
@Override
public ExperienceSourceManager<ClimbExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Material material) {
if (type == null)
return material.equals(Material.LADDER) || material.equals(Material.VINE) ||
material.equals(Material.WEEPING_VINES) || material.equals(Material.TWISTING_VINES) ||
material.equals(Material.WEEPING_VINES_PLANT) || material.equals(Material.TWISTING_VINES_PLANT);
if (type.equals(Material.WEEPING_VINES))
return material.equals(Material.WEEPING_VINES) || material.equals(Material.WEEPING_VINES_PLANT);
if (type.equals(Material.TWISTING_VINES))
return material.equals(Material.TWISTING_VINES) || material.equals(Material.TWISTING_VINES_PLANT);
return material.equals(type);
}
private static class Manager extends ExperienceSourceManager<ClimbExperienceSource> {
return new ExperienceSourceManager<ClimbExperienceSource>() {
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onClimb(PlayerMoveEvent e) {
double delta=e.getTo().getBlockY()-e.getFrom().getBlockY();
@ -70,5 +57,20 @@ public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Material material) {
if (type == null)
return material.equals(Material.LADDER) || material.equals(Material.VINE) ||
material.equals(Material.WEEPING_VINES) || material.equals(Material.TWISTING_VINES) ||
material.equals(Material.WEEPING_VINES_PLANT) || material.equals(Material.TWISTING_VINES_PLANT);
if (type.equals(Material.WEEPING_VINES))
return material.equals(Material.WEEPING_VINES) || material.equals(Material.WEEPING_VINES_PLANT);
if (type.equals(Material.TWISTING_VINES))
return material.equals(Material.TWISTING_VINES) || material.equals(Material.TWISTING_VINES_PLANT);
return material.equals(type);
}
}

View File

@ -3,8 +3,8 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
@ -30,19 +30,11 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
@Override
public ExperienceSourceManager<CraftItemExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<CraftItemExperienceSource> {
return new ExperienceSourceManager<CraftItemExperienceSource>() {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void a(CraftItemEvent event) {
if (event.getAction() == InventoryAction.NOTHING || event.getInventory().getResult() == null) return;
if (event.getAction() == InventoryAction.NOTHING ||
event.getInventory().getResult() == null) return;
PlayerData data = PlayerData.get((Player) event.getWhoClicked());
@ -72,7 +64,8 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
// First check
int newAmount = getAmount(event.getInventory().getMatrix()[index]);
if (newAmount >= oldAmount) return;
if (newAmount >= oldAmount)
return;
// Deduce amount crafted
int amountCrafted = (event.getClick().isShiftClick() ? oldAmount - newAmount : 1) * itemsCraftedPerRecipe;
@ -81,6 +74,13 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
source.giveExperience(data, amountCrafted, event.getInventory().getLocation());
});
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private int getAmount(@Nullable ItemStack item) {
return item == null || item.getType() == Material.AIR ? 0 : item.getAmount();
@ -102,4 +102,3 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
return index;
}
}
}

View File

@ -3,13 +3,13 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.damage.DamagePacket;
import io.lumine.mythic.lib.damage.DamageType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.attribute.Attribute;
import org.bukkit.event.EventHandler;
import java.util.Arrays;
@ -18,7 +18,7 @@ import java.util.stream.Collectors;
import static org.bukkit.event.EventPriority.MONITOR;
public class DamageDealtExperienceSource extends SpecificExperienceSource<Void> {
public class DamageDealtExperienceSource extends SpecificExperienceSource<DamageType> {
private final DamageType type;
/**
@ -28,40 +28,50 @@ public class DamageDealtExperienceSource extends SpecificExperienceSource<Void>
public DamageDealtExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type")) type = null;
if (!config.contains("type"))
type = null;
else {
String str = UtilityMethods.enumName(config.getString("type"));
//Checks if the damage type correspond to a value of the damage type enum
Validate.isTrue(Arrays.stream(DamageType.values()).map(Objects::toString).collect(Collectors.toList()).contains(str), "Type value not allowed. Type value allowed: magic, physical, weapon, skill, projectile," + " unarmed, on-hit, minion, dot.");
Validate.isTrue(Arrays.stream(DamageType.values()).map(Objects::toString).collect(Collectors.toList()).contains(str),
"Type value not allowed. Type value allowed: magic, physical, weapon, skill, projectile," +
" unarmed, on-hit, minion, dot.");
type = DamageType.valueOf(str);
}
}
@Override
public ExperienceSourceManager<DamageDealtExperienceSource> newManager() {
return new Manager();
return new ExperienceSourceManager<DamageDealtExperienceSource>() {
//It isn't triggered when the PlayerAttackEvent gets cancelled
@EventHandler(priority = MONITOR,ignoreCancelled = true)
public void onDamageDealt(PlayerAttackEvent e) {
PlayerData playerData = PlayerData.get(e.getPlayer());
for (DamageDealtExperienceSource source : getSources()) {
double value = 0;
for (DamagePacket packet : e.getDamage().getPackets()) {
for (DamageType damageType : packet.getTypes()) {
if (source.matchesParameter(playerData, damageType))
value += packet.getFinalValue();
}
}
source.giveExperience(playerData, value, null);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Void v) {
public boolean matchesParameter(PlayerData player, DamageType damageType) {
if (type == null) {
return true;
}
else {
return type.equals(damageType);
private static class Manager extends ExperienceSourceManager<DamageDealtExperienceSource> {
}
}
@EventHandler(priority = MONITOR, ignoreCancelled = true)
public void onDamageDealt(PlayerAttackEvent event) {
final PlayerData playerData = PlayerData.get(event.getPlayer());
for (DamageDealtExperienceSource source : getSources())
if (source.matches(playerData, null)) {
double value = source.type == null ? event.getDamage().getDamage() : event.getDamage().getDamage(source.type);
if (value == 0) continue;
// Cannot count more than the entity's max health
final double enemyMaxHealth = event.getEntity().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
value = Math.min(value, enemyMaxHealth);
source.giveExperience(playerData, value, null);
}
}
}
}

View File

@ -1,15 +1,13 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.util.Lazy;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.attribute.Attribute;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageEvent;
@ -43,40 +41,34 @@ public class DamageTakenExperienceSource extends SpecificExperienceSource<Entity
@Override
public ExperienceSourceManager<DamageTakenExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, EntityDamageEvent.DamageCause damageCause) {
if (player.getPlayer().isDead()) return false;
return cause == null || damageCause.equals(cause);
}
private static class Manager extends ExperienceSourceManager<DamageTakenExperienceSource> {
return new ExperienceSourceManager<DamageTakenExperienceSource>() {
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onDamageTaken(EntityDamageEvent event) {
if (!UtilityMethods.isRealPlayer(event.getEntity())) return;
final PlayerData playerData = PlayerData.get((Player) event.getEntity());
final Lazy<Double> effectiveDamage = Lazy.of(() -> {
final double eventDamage = event.getDamage();
final double maxHealth = ((Player) event.getEntity()).getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
return Math.min(eventDamage, maxHealth);
});
// Wait 2 tick to check if the player died
public void onDamageTaken(EntityDamageEvent e) {
if (e.getEntity() instanceof Player && !e.getEntity().hasMetadata("NPC")) {
double amount = e.getDamage();
PlayerData playerData = PlayerData.get((OfflinePlayer) e.getEntity());
//We wait 2 tick to check if the player is Dead
new BukkitRunnable() {
@Override
public void run() {
for (DamageTakenExperienceSource source : getSources())
if (source.matchesParameter(playerData, event.getCause())) {
// System.out.println("-> " + effectiveDamage.get());
source.giveExperience(playerData, effectiveDamage.get(), null);
for (DamageTakenExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getCause()))
source.giveExperience(playerData, amount, null);
}
}
}.runTaskLater(MMOCore.plugin, 2);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, EntityDamageEvent.DamageCause damageCause) {
if (player.getPlayer().isDead())
return false;
if (cause == null)
return true;
return damageCause.equals(cause);
}
}

View File

@ -33,18 +33,7 @@ public class EatExperienceSource extends SpecificExperienceSource<ItemStack> {
@Override
public ExperienceSourceManager<EatExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
if(type==null)
return true;
return type.equals(obj.getType());
}
private static class Manager extends ExperienceSourceManager<EatExperienceSource> {
return new ExperienceSourceManager<EatExperienceSource>() {
@EventHandler(priority = MONITOR,ignoreCancelled = true)
public void a(PlayerItemConsumeEvent e) {
@ -56,5 +45,14 @@ public class EatExperienceSource extends SpecificExperienceSource<ItemStack> {
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
if(type==null)
return true;
return type.equals(obj.getType());
}
}

View File

@ -4,9 +4,9 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.EventHandler;
@ -41,12 +41,9 @@ public class EnchantItemExperienceSource extends ExperienceSource<Void> {
@Override
public ExperienceSourceManager<EnchantItemExperienceSource> newManager() {
return new Manager();
}
return new ExperienceSourceManager<EnchantItemExperienceSource>() {
private static class Manager extends ExperienceSourceManager<EnchantItemExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(EnchantItemEvent event) {
PlayerData player = PlayerData.get(event.getEnchanter());
for (EnchantItemExperienceSource source : getSources())
@ -63,8 +60,9 @@ public class EnchantItemExperienceSource extends ExperienceSource<Void> {
double exp = 0;
for (Entry<Enchantment, Integer> entry : applicableEnchants.entrySet())
exp += MMOCore.plugin.enchantManager.getBaseExperience(entry.getKey()) * entry.getValue();
source.getDispenser().giveExperience(player, exp, event.getEnchantBlock().getLocation(), EXPSource.SOURCE);
getDispenser().giveExperience(player, exp, event.getEnchantBlock().getLocation(), EXPSource.SOURCE);
}
}
};
}
}

View File

@ -2,8 +2,8 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Material;
import org.bukkit.entity.Item;
@ -25,17 +25,9 @@ public class FishItemExperienceSource extends SpecificExperienceSource<ItemStack
@Override
public ExperienceSourceManager<FishItemExperienceSource> newManager() {
return new Manager();
}
return new ExperienceSourceManager<FishItemExperienceSource>() {
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
return obj.getType() == material;
}
private static class Manager extends ExperienceSourceManager<FishItemExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(PlayerFishEvent event) {
if (event.getState() == State.CAUGHT_FISH) {
ItemStack caught = ((Item) event.getCaught()).getItemStack();
@ -48,5 +40,11 @@ public class FishItemExperienceSource extends SpecificExperienceSource<ItemStack
source.giveExperience(data, caught.getAmount(), event.getHook().getLocation().add(0, 1.0f, 0));
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
return obj.getType() == material;
}
}

View File

@ -33,15 +33,7 @@ public class FromExperienceSource extends ExperienceSource {
@Override
public ExperienceSourceManager<FromExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return false;
}
private static class Manager extends ExperienceSourceManager<FromExperienceSource> {
return new ExperienceSourceManager<>() {
/**
* Used to register all the children experience sources.
@ -50,5 +42,11 @@ public class FromExperienceSource extends ExperienceSource {
public void registerSource(FromExperienceSource source) {
source.experienceSources.forEach(expSource -> MMOCore.plugin.experience.registerSource(expSource));
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return false;
}
}

View File

@ -38,16 +38,7 @@ public class KillMobExperienceSource extends SpecificExperienceSource<Entity> {
@Override
public ExperienceSourceManager<KillMobExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Entity obj) {
return obj.getType() == type && (displayName == null || displayName.equals(obj.getCustomName()));
}
private static class Manager extends ExperienceSourceManager<KillMobExperienceSource> {
return new ExperienceSourceManager<KillMobExperienceSource>() {
/**
* This map is used to keep track of the last player who
@ -80,5 +71,11 @@ public class KillMobExperienceSource extends SpecificExperienceSource<Entity> {
if (source.matches(data, event.getEntity()))
source.giveExperience(data, 1, MMOCoreUtils.getCenterLocation(event.getEntity()));
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Entity obj) {
return obj.getType() == type && (displayName == null || displayName.equals(obj.getCustomName()));
}
}

View File

@ -1,11 +1,10 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -22,7 +21,7 @@ public class MineBlockExperienceSource extends SpecificExperienceSource<Material
/**
* Set to false by default.
* <p>
*
* When set to true, the exp source will trigger when breaking
* blocks that were placed by players. This can be used for crops
*/
@ -40,36 +39,37 @@ public class MineBlockExperienceSource extends SpecificExperienceSource<Material
@Override
public ExperienceSourceManager<MineBlockExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<MineBlockExperienceSource> {
return
new ExperienceSourceManager<MineBlockExperienceSource>() {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BlockBreakEvent event) {
if (event.getPlayer().getGameMode() != GameMode.SURVIVAL) return;
if (UtilityMethods.isFake(event)) return;
if (event.getPlayer().getGameMode() != GameMode.SURVIVAL)
return;
PlayerData data = PlayerData.get(event.getPlayer());
for (MineBlockExperienceSource source : getSources()) {
if (source.silkTouch && hasSilkTouch(event.getPlayer().getInventory().getItemInMainHand())) continue;
if (source.silkTouch && hasSilkTouch(event.getPlayer().getInventory().getItemInMainHand()))
continue;
if (source.crop && !MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock()))
continue;
if (!source.playerPlaced && event.getBlock().hasMetadata("player_placed")) continue;
if (!source.playerPlaced && event.getBlock().hasMetadata("player_placed"))
continue;
if (source.matches(data, event.getBlock().getType()))
source.giveExperience(data, 1, event.getBlock().getLocation());
}
}
};
}
private boolean hasSilkTouch(ItemStack item) {
return item != null && item.hasItemMeta() && item.getItemMeta().hasEnchant(Enchantment.SILK_TOUCH);
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
}

View File

@ -36,7 +36,27 @@ public class MoveExperienceSource extends SpecificExperienceSource {
@Override
public ExperienceSourceManager<MoveExperienceSource> newManager() {
return new Manager();
return new ExperienceSourceManager<MoveExperienceSource>() {
@EventHandler(priority = MONITOR,ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
double deltax = e.getTo().getBlockX() - e.getFrom().getBlockX();
double deltay = e.getTo().getBlockY() - e.getFrom().getBlockY();
double deltaz = e.getTo().getBlockZ() - e.getFrom().getBlockZ();
if (deltax != 0 || deltay != 0 || deltaz != 0) {
double delta = Math.sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
if (e.getPlayer().hasMetadata("NPC"))
return;
Player player = e.getPlayer();
PlayerData playerData = PlayerData.get(player);
for (MoveExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, null)) {
giveExperience(playerData, delta, null);
}
}
}
}
};
}
@Override
@ -62,24 +82,4 @@ public class MoveExperienceSource extends SpecificExperienceSource {
}
}
private static class Manager extends ExperienceSourceManager<MoveExperienceSource> {
@EventHandler(priority = MONITOR, ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
double deltax = e.getTo().getBlockX() - e.getFrom().getBlockX();
double deltay = e.getTo().getBlockY() - e.getFrom().getBlockY();
double deltaz = e.getTo().getBlockZ() - e.getFrom().getBlockZ();
if (deltax != 0 || deltay != 0 || deltaz != 0) {
double delta = Math.sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
if (e.getPlayer().hasMetadata("NPC"))
return;
Player player = e.getPlayer();
PlayerData playerData = PlayerData.get(player);
for (MoveExperienceSource source : getSources())
if (source.matchesParameter(playerData, null))
source.giveExperience(playerData, delta, null);
}
}
}
}

View File

@ -2,8 +2,8 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -23,16 +23,7 @@ public class PlaceBlockExperienceSource extends SpecificExperienceSource<Materia
@Override
public ExperienceSourceManager<PlaceBlockExperienceSource> newManager() {
return new Manager();
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<PlaceBlockExperienceSource> {
return new ExperienceSourceManager<PlaceBlockExperienceSource>() {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BlockPlaceEvent event) {
@ -44,5 +35,11 @@ public class PlaceBlockExperienceSource extends SpecificExperienceSource<Materia
if (source.matches(data, event.getBlock().getType()))
source.giveExperience(data, 1, event.getBlock().getLocation());
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
}

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
@ -15,13 +14,14 @@ import org.bukkit.scheduler.BukkitRunnable;
import java.util.Objects;
public class PlayExperienceSource extends SpecificExperienceSource {
private final World world;
private final double x1, x2, z1, z2;
private final boolean inCombat;
/**
* Experience source giving the specified amount of xp to all the players online each second in certain world bounds.
* If no bounds are given, it will give the xp to every player online. You can also specify if the player
* If no bounds are given, it will give the xp to every player online. You can also specifiy if the player
* has to be inCombat or not to get the xp.
*/
public PlayExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
@ -47,7 +47,7 @@ public class PlayExperienceSource extends SpecificExperienceSource {
@Override
public ExperienceSourceManager<PlayExperienceSource> newManager() {
return new Manager();
return new PlayingExperienceSourceManager();
}
@ -64,19 +64,20 @@ public class PlayExperienceSource extends SpecificExperienceSource {
}
private static class Manager extends ExperienceSourceManager<PlayExperienceSource> {
private class PlayingExperienceSourceManager extends ExperienceSourceManager<PlayExperienceSource> {
public Manager() {
public PlayingExperienceSourceManager() {
new BukkitRunnable() {
@Override
public void run() {
Bukkit.getOnlinePlayers().forEach(player -> {
if (UtilityMethods.isRealPlayer(player)) {
Bukkit.getOnlinePlayers().forEach((player) -> {
if (!player.hasMetadata("NPC")) {
PlayerData playerData = PlayerData.get(player);
for (PlayExperienceSource source : getSources())
for (PlayExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, null))
source. giveExperience(playerData, 1, null);
giveExperience(playerData, 1, null);
}
}
});
}

View File

@ -1,8 +1,7 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.util.FlushableRegistry;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
@ -17,8 +16,10 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -29,7 +30,8 @@ public class ProjectileExperienceSource extends SpecificExperienceSource<Project
public ProjectileExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type")) projectileType = null;
if (!config.contains("type"))
projectileType = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(Arrays.stream(ProjectileType.values()).map(ProjectileType::toString).collect(Collectors.toList()).contains(str));
@ -39,17 +41,76 @@ public class ProjectileExperienceSource extends SpecificExperienceSource<Project
@Override
public ExperienceSourceManager<ProjectileExperienceSource> newManager() {
return new Manager();
return new ExperienceSourceManager<ProjectileExperienceSource>() {
HashMap<Projectile, Location> projectiles = new HashMap<>();
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onHit(ProjectileHitEvent e) {
if (e.getHitBlock() != null && projectiles.containsKey(e.getEntity()))
projectiles.remove(e.getEntity());
}
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onDamage(EntityDamageByEntityEvent e) {
if (e.getEntity() instanceof Projectile) {
Projectile projectile = (Projectile) e.getEntity();
if (!projectiles.containsKey(projectile))
return;
if (projectile.getShooter() instanceof Player && !((Player) projectile.getShooter()).hasMetadata("NPC")) {
Player player = (Player) projectile.getShooter();
PlayerData playerData = PlayerData.get(player);
double distance = projectiles.get(projectile).distance(e.getEntity().getLocation());
for (ProjectileExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, projectile))
source.giveExperience(playerData, e.getFinalDamage() * distance, null);
}
}
projectiles.remove(projectile);
}
}
//Mark every arrow with the the location at which it was shot to calculate the distance
@EventHandler
public void onLaunch(ProjectileLaunchEvent e) {
if (e.getEntity().getShooter() instanceof Player) {
Player player = (Player) e.getEntity().getShooter();
if (player.hasMetadata("NPC"))
return;
projectiles.put(e.getEntity(), e.getLocation());
//Remove the projectile 15 s after it was launched
new BukkitRunnable() {
@Override
public void run() {
projectiles.remove(e.getEntity());
}
}.runTaskLater(MMOCore.plugin, 60 * 20L);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Projectile projectile) {
if (projectileType == null) return true;
if (projectileType == null)
return true;
return projectileType.matches(projectile);
}
public enum ProjectileType {
ARROW((p) -> p instanceof Arrow), TRIDENT((p) -> p instanceof Trident);
ARROW((p) -> p instanceof Arrow),
TRIDENT((p) -> p instanceof Trident);
private final Function<Projectile, Boolean> matching;
@ -63,41 +124,4 @@ public class ProjectileExperienceSource extends SpecificExperienceSource<Project
}
}
private static class Manager extends ExperienceSourceManager<ProjectileExperienceSource> {
private final FlushableRegistry<Projectile, Location> projectiles = new FlushableRegistry<>((proj, loc) -> proj.isDead(), 20 * 60);
@EventHandler(priority = HIGHEST, ignoreCancelled = true)
public void onHit(ProjectileHitEvent e) {
if (e.getHitBlock() != null) projectiles.getRegistry().remove(e.getEntity());
}
@EventHandler(priority = HIGHEST, ignoreCancelled = true)
public void onDamage(EntityDamageByEntityEvent e) {
if (e.getEntity() instanceof Projectile) {
Projectile projectile = (Projectile) e.getEntity();
Location loc = projectiles.getRegistry().get(projectile);
if (loc == null) return;
if (projectile.getShooter() instanceof Player && !((Player) projectile.getShooter()).hasMetadata("NPC")) {
Player player = (Player) projectile.getShooter();
PlayerData playerData = PlayerData.get(player);
double distance = loc.distance(e.getEntity().getLocation());
for (ProjectileExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, projectile))
source.giveExperience(playerData, e.getFinalDamage() * distance, null);
}
}
}
}
// Mark every arrow with the location at which it was shot to calculate the distance
@EventHandler
public void onLaunch(ProjectileLaunchEvent e) {
if (e.getEntity().getShooter() instanceof Player && UtilityMethods.isRealPlayer((Player) e.getEntity().getShooter())) {
projectiles.getRegistry().put(e.getEntity(), e.getLocation());
}
}
}
}

View File

@ -41,14 +41,14 @@ public class RepairItemExperienceSource extends ExperienceSource<ItemStack> {
@Override
public ExperienceSourceManager<RepairItemExperienceSource> newManager() {
return new Manager();
return new CustomExperienceManager();
}
private static class Manager extends ExperienceSourceManager<RepairItemExperienceSource> {
private class CustomExperienceManager extends ExperienceSourceManager<RepairItemExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(InventoryClickEvent event) {
if (event.getInventory() == null || event.getInventory().getType() != InventoryType.ANVIL || event.getRawSlot() != 2)
if (event.getInventory() == null || event.getInventory().getType() != InventoryType.ANVIL || event.getSlot() != 2)
return;
// Check if there's exp associated to it
@ -80,7 +80,7 @@ public class RepairItemExperienceSource extends ExperienceSource<ItemStack> {
*/
final double exp = MMOCore.plugin.smithingManager.getBaseExperience(item.getType())
* Math.max(0, ((Damageable) old.getItemMeta()).getDamage() - ((Damageable) item.getItemMeta()).getDamage()) / 100;
source.getDispenser().giveExperience(data, exp, data.getPlayer().getLocation(), EXPSource.SOURCE);
getDispenser().giveExperience(data, exp, data.getPlayer().getLocation(), EXPSource.SOURCE);
}
}
}

View File

@ -1,13 +1,12 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import org.apache.commons.lang.Validate;
import org.bukkit.event.EventHandler;
@ -22,37 +21,39 @@ public class ResourceExperienceSource extends SpecificExperienceSource<PlayerRes
*/
public ResourceExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type")) resource = null;
if (!config.contains("type"))
resource = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(str.equals("MANA") || str.equals("STELLIUM") || str.equals("STAMINA"), "ResourceExperienceSource problem: The resource can only be mana, stamina or STELLIUM");
Validate.isTrue(str.equals("MANA") || str.equals("STELLIUM") || str.equals("STAMINA"),
"ResourceExperienceSource problem: The resource can only be mana, stamina or STELLIUM");
resource = PlayerResource.valueOf(str);
}
}
@Override
public ExperienceSourceManager<ResourceExperienceSource> newManager() {
return new Manager();
return new ExperienceSourceManager<ResourceExperienceSource>() {
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onResource(PlayerResourceUpdateEvent e) {
if (e.getPlayer().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get(e.getPlayer());
if(e.getAmount()<0)
for (ResourceExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getResource()))
source.giveExperience(playerData, -e.getAmount(), null);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, PlayerResource obj) {
if (resource == null) return !obj.equals(PlayerResource.HEALTH);
if (resource == null)
return !obj.equals(PlayerResource.HEALTH);
return resource.equals(obj);
}
private static class Manager extends ExperienceSourceManager<ResourceExperienceSource> {
@EventHandler(priority = HIGHEST, ignoreCancelled = true)
public void onResource(PlayerResourceUpdateEvent event) {
if (!UtilityMethods.isRealPlayer(event.getPlayer())) return;
PlayerData playerData = PlayerData.get(event.getPlayer());
if (event.getAmount() >= 0) return;
for (ResourceExperienceSource source : getSources())
if (source.matchesParameter(playerData, event.getResource()))
source.giveExperience(playerData, -event.getAmount(), null);
}
}
}

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
@ -41,7 +40,29 @@ public class RideExperienceSource extends SpecificExperienceSource<EntityType> {
@Override
public ExperienceSourceManager<RideExperienceSource> newManager() {
return new Manager();
return new ExperienceSourceManager<RideExperienceSource>() {
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onRide(PlayerMoveEvent e) {
if (e.getPlayer().isInsideVehicle()) {
double deltax = e.getTo().getBlockX() - e.getFrom().getBlockX();
double deltay = e.getTo().getBlockY() - e.getFrom().getBlockY();
double deltaz = e.getTo().getBlockZ() - e.getFrom().getBlockZ();
if (deltax != 0 && deltay != 0 && deltaz != 0) {
double delta = Math.sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
if (e.getPlayer().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get(e.getPlayer());
Entity vehicle = e.getPlayer().getVehicle();
for (RideExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, vehicle.getType()))
giveExperience(playerData, e.getFrom().distance(e.getTo()), null);
}
}
}
}
};
}
@Override
@ -51,25 +72,4 @@ public class RideExperienceSource extends SpecificExperienceSource<EntityType> {
return type.equals(obj);
}
private static class Manager extends ExperienceSourceManager<RideExperienceSource> {
@EventHandler(priority = HIGHEST, ignoreCancelled = true)
public void onRide(PlayerMoveEvent event) {
if (!event.getPlayer().isInsideVehicle()) return;
double deltax = event.getTo().getBlockX() - event.getFrom().getBlockX();
double deltay = event.getTo().getBlockY() - event.getFrom().getBlockY();
double deltaz = event.getTo().getBlockZ() - event.getFrom().getBlockZ();
if (deltax != 0 || deltay != 0 || deltaz != 0) {
if (!UtilityMethods.isRealPlayer(event.getPlayer())) return;
PlayerData playerData = PlayerData.get(event.getPlayer());
Entity vehicle = event.getPlayer().getVehicle();
for (RideExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, vehicle.getType()))
source.giveExperience(playerData, event.getFrom().distance(event.getTo()), null);
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More