Compare commits

..

5 Commits

258 changed files with 3872 additions and 5459 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

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

View File

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

View File

@ -2,143 +2,47 @@ package net.Indyuce.mmocore.api;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import org.bukkit.OfflinePlayer;
import net.md_5.bungee.api.ChatMessageType; import org.bukkit.command.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player; 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.Collection;
import java.util.List; import java.util.List;
public class ConfigMessage { public class ConfigMessage {
private final String key; private final List<String> messages;
private final List<String> lines = new ArrayList<>();
private final boolean papiPlaceholders, actionbar, raw;
private ConfigMessage(@NotNull String key) { public ConfigMessage(String key) {
this.key = key; messages = MMOCore.plugin.configManager.getMessage(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);
} }
// Does message include placeholders public ConfigMessage addPlaceholders(String... placeholders) {
boolean hasPlaceholders = false; for (int n = 0; n < messages.size(); n++) {
for (String str : lines) String line = messages.get(n);
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
for (int j = 0; j < placeholders.length - 1; j += 2) { for (int j = 0; j < placeholders.length - 1; j += 2) {
final String placeholder = String.valueOf(placeholders[j]); String placeholder = placeholders[j];
line = line.replace("{" + placeholder + "}", String.valueOf(placeholders[j + 1])); if (line.contains("{" + placeholder + "}"))
line = line.replace("{" + placeholder + "}", placeholders[j + 1]);
} }
messages.set(n, line);
lines.set(n, line);
} }
return this; return this;
} }
@Deprecated public void send(CommandSender sender) {
public void sendAsJSon(Player player) { messages.forEach(line -> sender.sendMessage(format(sender, line)));
send(player);
}
public void send(Player player) {
for (String line : lines) send(player, line);
} }
public void send(Collection<? extends Player> players) { 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))));
} }
/** public void sendAsJSon(Player player) {
* Sends a line of text to a target player messages.forEach(line -> MythicLib.plugin.getVersion().getWrapper().sendJson(player, format(player, line)));
*
* @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;
} }
// Normal sender private String format(CommandSender sender, String input) {
if (this.raw) { String str = MythicLib.plugin.parseColors(input);
if (actionbar) MythicLib.plugin.getVersion().getWrapper().sendActionBarRaw(player, rawMessage); return sender instanceof Player ? MMOCore.plugin.placeholderParser.parse((OfflinePlayer) sender, str) : str;
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;
} }
} }

View File

@ -25,7 +25,7 @@ public class MMOCoreAPI {
} }
public PlayerData getPlayerData(OfflinePlayer player) { public PlayerData getPlayerData(OfflinePlayer player) {
return PlayerData.get(player); return PlayerData.get(player.getUniqueId());
} }
public boolean isInSameParty(Player player1, Player player2) { public boolean isInSameParty(Player player1, Player player2) {

View File

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

View File

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

View File

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

View File

@ -1,31 +1,29 @@
package net.Indyuce.mmocore.api.block; package net.Indyuce.mmocore.api.block;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface BlockType { public interface BlockType {
/** /**
* Called when placing temporary blocks * 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 * 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 * 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 * broken. This method is used to prevent non mature crops from being broken
* for example * for example
*/ */
boolean breakRestrictions(@NotNull Block block); boolean breakRestrictions(Block block);
int hashCode();
boolean equals(@Nullable Object obj);
} }

View File

@ -1,14 +1,13 @@
package net.Indyuce.mmocore.api.block; 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 net.Indyuce.mmocore.api.util.MMOCoreUtils;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block; 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 { public class SkullBlockType implements BlockType {
private final String value; private final String value;
@ -30,7 +29,7 @@ public class SkullBlockType implements BlockType {
@Override @Override
public void place(RegeneratingBlock block) { public void place(RegeneratingBlock block) {
Location loc = block.getLocation(); 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 // save skull orientation if replaced block is a player head
if (MMOCoreUtils.isPlayerHead(block.getBlockData().getMaterial())) if (MMOCoreUtils.isPlayerHead(block.getBlockData().getMaterial()))
@ -49,25 +48,12 @@ public class SkullBlockType implements BlockType {
} }
@Override @Override
public String display() { public String generateKey() {
return "Skull{" + value + "}"; return "vanilla-skull-" + value;
} }
@Override @Override
public boolean breakRestrictions(Block block) { public boolean breakRestrictions(Block block) {
return true; 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; 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.apache.commons.lang.Validate;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -9,7 +7,8 @@ import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable; import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData; 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 { public class VanillaBlockType implements BlockType {
private final Material type; private final Material type;
@ -59,25 +58,12 @@ public class VanillaBlockType implements BlockType {
} }
@Override @Override
public String display() { public String generateKey() {
return "Vanilla{" + type.name() + "}"; return "vanilla-block-" + type.name();
} }
@Override @Override
public boolean breakRestrictions(Block block) { public boolean breakRestrictions(Block block) {
return age == 0 || (block.getBlockData() instanceof Ageable && ((Ageable) block.getBlockData()).getAge() >= age); 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 java.util.UUID;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.util.item.CurrencyItemBuilder; import net.Indyuce.mmocore.util.item.CurrencyItemBuilder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
@ -39,7 +38,7 @@ public class Withdraw implements Listener {
return; return;
withdrawing.add(player.getUniqueId()); withdrawing.add(player.getUniqueId());
ConfigMessage.fromKey("withdrawing").send(player); MMOCore.plugin.configManager.getSimpleMessage("withdrawing").send(player);
Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin); Bukkit.getPluginManager().registerEvents(this, MMOCore.plugin);
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, 20 * 20); Bukkit.getScheduler().runTaskLater(MMOCore.plugin, this::close, 20 * 20);
} }
@ -61,7 +60,7 @@ public class Withdraw implements Listener {
if (!event.getPlayer().equals(player)) if (!event.getPlayer().equals(player))
return; return;
ConfigMessage.fromKey("withdraw-cancel").send(player); MMOCore.plugin.configManager.getSimpleMessage("withdraw-cancel").send(player);
close(); close();
} }
@ -76,13 +75,13 @@ public class Withdraw implements Listener {
try { try {
worth = Integer.parseInt(event.getMessage()); worth = Integer.parseInt(event.getMessage());
} catch (Exception e) { } 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; return;
} }
int left = (int) (MMOCore.plugin.economy.getEconomy().getBalance(player) - worth); int left = (int) (MMOCore.plugin.economy.getEconomy().getBalance(player) - worth);
if (left < 0) { 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; return;
} }
@ -92,7 +91,7 @@ public class Withdraw implements Listener {
MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, worth); MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, worth);
withdrawAlgorythm(worth); withdrawAlgorythm(worth);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); 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; import org.bukkit.event.HandlerList;
/** /**
* @deprecated Use {@link io.lumine.mythic.lib.api.event.SynchronizedDataLoadEvent} instead * @deprecated Use {@link AsyncPlayerDataLoadEvent} instead
*/ */
@Deprecated @Deprecated
public class PlayerDataLoadEvent extends PlayerDataEvent { public class PlayerDataLoadEvent extends PlayerDataEvent {

View File

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

View File

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

View File

@ -23,7 +23,9 @@ public enum PlayerActivity {
CAST_SKILL(() -> MMOCore.plugin.configManager.globalSkillCooldown), CAST_SKILL(() -> MMOCore.plugin.configManager.globalSkillCooldown),
; //Added by Kilo for the Timeout System (ENTER_CASTING). The EXIT_CASTING is unused, but tracked.
ENTER_CASTING(null),
EXIT_CASTING(null);
private final Provider<Long> timeout; private final Provider<Long> timeout;

View File

@ -2,10 +2,11 @@ package net.Indyuce.mmocore.api.player;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData; 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.data.SynchronizedDataHolder;
import io.lumine.mythic.lib.player.cooldown.CooldownMap; import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import io.lumine.mythic.lib.util.Closeable; import io.lumine.mythic.lib.util.Closeable;
import io.lumine.mythic.lib.version.VParticle;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
@ -21,13 +22,13 @@ import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.social.FriendRequest; import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats; import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.quest.PlayerQuests; 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.Trigger;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.ExperienceTableClaimer;
import net.Indyuce.mmocore.experience.PlayerProfessions; import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem; import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.guild.provided.Guild;
@ -45,7 +46,6 @@ import net.Indyuce.mmocore.skill.binding.BoundSkillInfo;
import net.Indyuce.mmocore.skill.binding.SkillSlot; import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.skill.cast.SkillCastingInstance; import net.Indyuce.mmocore.skill.cast.SkillCastingInstance;
import net.Indyuce.mmocore.skill.cast.SkillCastingMode; import net.Indyuce.mmocore.skill.cast.SkillCastingMode;
import net.Indyuce.mmocore.skilltree.NodeIncrementResult;
import net.Indyuce.mmocore.skilltree.SkillTreeNode; import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.SkillTreeStatus; import net.Indyuce.mmocore.skilltree.SkillTreeStatus;
import net.Indyuce.mmocore.skilltree.tree.SkillTree; import net.Indyuce.mmocore.skilltree.tree.SkillTree;
@ -64,28 +64,25 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; 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 * Can be null, the {@link #getProfess()} method will return the
* player class, or the default one if this field is null. * 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 @Nullable
private PlayerClass profess; private PlayerClass profess;
private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints; private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints, skillTreeReallocationPoints, skillReallocationPoints;
private double experience; 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 Guild guild;
private SkillCastingInstance skillCasting; private SkillCastingInstance skillCasting;
private final PlayerQuests questData; private final PlayerQuests questData;
@ -93,11 +90,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
private final List<UUID> friends = new ArrayList<>(); private final List<UUID> friends = new ArrayList<>();
/** /**
* TODO Use {@link #hasUnlocked(Unlockable)} instead * @deprecated 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 @Deprecated
private final Set<String> waypoints = new HashSet<>(); private final Set<String> waypoints = new HashSet<>();
@ -109,13 +102,17 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
private final Map<PlayerActivity, Long> lastActivity = new HashMap<>(); private final Map<PlayerActivity, Long> lastActivity = new HashMap<>();
private final CombatHandler combat = new CombatHandler(this); 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. * Cached for easier access. Current status of each skill tree node.
*/ */
private final Map<SkillTreeNode, SkillTreeStatus> nodeStates = new HashMap<>(); private final Map<SkillTreeNode, SkillTreeStatus> nodeStates = new HashMap<>();
private final Map<SkillTreeNode, Integer> nodeLevels = new HashMap<>(); private final Map<SkillTreeNode, Integer> nodeLevels = new HashMap<>();
private final Map<String, Integer> skillTreePoints = 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". * Saves the namespacedkeys of the items that have been unlocked in the form "namespace:key".
@ -127,17 +124,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
/** /**
* Saves the amount of times the player has claimed some * Saves the amount of times the player has claimed some
* item in any experience table. The key used in the map * exp item in exp tables, for both exp tables used
* is the identifier of the exp table item.
*/ */
private final Map<String, Integer> tableItemClaims = new HashMap<>(); private final Map<String, Integer> tableItemClaims = new HashMap<>();
// NON-FINAL player data stuff made public to facilitate field change // NON-FINAL player data stuff made public to facilitate field change
public boolean noCooldown; public boolean noCooldown;
public long lastDropEvent;
public PlayerData(MMOPlayerData mmoData) { public PlayerData(MMOPlayerData mmoData) {
super(MMOCore.plugin, mmoData); super(mmoData);
questData = new PlayerQuests(this); questData = new PlayerQuests(this);
playerStats = new PlayerStats(this); playerStats = new PlayerStats(this);
@ -154,9 +149,13 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void reload() { public void reload() {
try { try {
profess = profess == null ? null : MMOCore.plugin.classManager.get(profess.getId()); profess = profess == null ? null : MMOCore.plugin.classManager.get(profess.getId());
getStats().updateStats();
} catch (NullPointerException exception) { } catch (NullPointerException exception) {
MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data."); MMOCore.log(Level.SEVERE, "[Userdata] Could not find class " + getProfess().getId() + " while refreshing player data.");
} }
//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)));
final Iterator<Map.Entry<Integer, BoundSkillInfo>> ite = new HashMap(boundSkills).entrySet().iterator(); final Iterator<Map.Entry<Integer, BoundSkillInfo>> ite = new HashMap(boundSkills).entrySet().iterator();
while (ite.hasNext()) while (ite.hasNext())
try { try {
@ -178,42 +177,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
if (!nodeLevels.containsKey(node)) nodeLevels.put(node, 0); if (!nodeLevels.containsKey(node)) nodeLevels.put(node, 0);
setupSkillTree(); setupSkillTree();
applyTemporaryTriggers();
getStats().updateStats();
}
@Deprecated
public void setupRemovableTrigger() {
applyTemporaryTriggers();
}
/**
* 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
for (Profession profession : MMOCore.plugin.professionManager.getAll())
if (profession.hasExperienceTable())
profession.getExperienceTable().applyTemporaryTriggers(this, profession);
// Experience tables from skill tree nodes
for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().applyTemporaryTriggers(this, node);
} }
public void setupSkillTree() { public void setupSkillTree() {
@ -221,27 +184,26 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Node states setup // Node states setup
for (SkillTree skillTree : getProfess().getSkillTrees()) for (SkillTree skillTree : getProfess().getSkillTrees())
skillTree.setupNodeStates(this); skillTree.setupNodeStates(this);
// Stat triggers setup
for (SkillTree skillTree : MMOCore.plugin.skillTreeManager.getAll())
for (SkillTreeNode node : skillTree.getNodes())
node.getExperienceTable().claimRemovableTrigger(this, node);
} }
public int getPointsSpent(@NotNull SkillTree skillTree) {
return skillTreePointsSpent.getOrDefault(skillTree, 0);
}
@Deprecated
public int getPointSpent(SkillTree skillTree) { public int getPointSpent(SkillTree skillTree) {
return getPointsSpent(skillTree); return pointSpent.getOrDefault(skillTree, 0);
} }
public void setSkillTreePoints(@NotNull String treeId, int points) { public void setSkillTreePoints(String treeId, int points) {
if (points <= 0) skillTreePoints.remove(treeId); skillTreePoints.put(treeId, points);
else skillTreePoints.put(treeId, points);
} }
public void giveSkillTreePoints(@NotNull String id, int val) { public void giveSkillTreePoints(String id, int val) {
skillTreePoints.merge(id, Math.max(0, val), (points, ignored) -> Math.max(0, points + 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(); return nodeLevels.keySet().stream().filter(node -> node.getTree().equals(skillTree)).mapToInt(node -> nodeLevels.get(node) * node.getSkillTreePointsConsumed()).sum();
} }
@ -249,7 +211,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* Make a copy to make sure that the object * Make a copy to make sure that the object
* created is independent of the state of playerData. * created is independent of the state of playerData.
*/ */
@NotNull
public Map<String, Integer> mapSkillTreePoints() { public Map<String, Integer> mapSkillTreePoints() {
return new HashMap(skillTreePoints); return new HashMap(skillTreePoints);
} }
@ -262,6 +223,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return result; 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() { public Set<Map.Entry<String, Integer>> getNodeLevelsEntrySet() {
HashMap<String, Integer> nodeLevelsString = new HashMap<>(); HashMap<String, Integer> nodeLevelsString = new HashMap<>();
for (SkillTreeNode node : nodeLevels.keySet()) for (SkillTreeNode node : nodeLevels.keySet())
@ -270,8 +240,13 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
} }
public void resetTriggerStats() { public void resetTriggerStats() {
getMMOPlayerData().getStatMap().getInstances().forEach(statInstance -> statInstance.removeIf(Trigger.STAT_MODIFIER_KEY::equals)); for (StatInstance instance : getMMOPlayerData().getStatMap().getInstances()) {
getMMOPlayerData().getSkillModifierMap().removeModifiers(Trigger.STAT_MODIFIER_KEY); Iterator<StatModifier> iter = instance.getModifiers().iterator();
while (iter.hasNext()) {
StatModifier modifier = iter.next();
if (modifier.getKey().startsWith(StatTrigger.TRIGGER_PREFIX)) iter.remove();
}
}
} }
@Override @Override
@ -281,48 +256,16 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return mapped; return mapped;
} }
@Deprecated public void clearNodeLevels() {
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
nodeLevels.clear(); nodeLevels.clear();
nodeStates.clear(); pointSpent.clear();
skillTreePointsSpent.clear();
// Skill tree points
skillTreePoints.clear();
// Clear node claim count
tableItemClaims.keySet().removeIf(s -> s.startsWith(SkillTreeNode.KEY_PREFIX));
} }
@NotNull public boolean canIncrementNodeLevel(SkillTreeNode node) {
public NodeIncrementResult canIncrementNodeLevel(@NotNull SkillTreeNode node) { SkillTreeStatus skillTreeStatus = nodeStates.get(node);
final SkillTreeStatus skillTreeStatus = nodeStates.get(node); //Check the State of the node
if (skillTreeStatus != SkillTreeStatus.UNLOCKED && skillTreeStatus != SkillTreeStatus.UNLOCKABLE) return false;
// Check node state return node.hasPermissionRequirement(this) && getNodeLevel(node) < node.getMaxLevel() && (skillTreePoints.getOrDefault(node.getTree().getId(), 0) + skillTreePoints.getOrDefault("global", 0) >= node.getSkillTreePointsConsumed());
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;
} }
/** /**
@ -330,39 +273,32 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* Consumes skill tree points from the tree first and then consumes the * Consumes skill tree points from the tree first and then consumes the
* global skill-tree points ('all') * global skill-tree points ('all')
*/ */
public void incrementNodeLevel(@NotNull SkillTreeNode node) { public void incrementNodeLevel(SkillTreeNode node) {
final int newLevel = addNodeLevels(node, 1); setNodeLevel(node, getNodeLevel(node) + 1);
node.updateAdvancement(this, newLevel); // Claim the node exp table // Claims the nodes experience table.
node.getExperienceTable().claim(this, getNodeLevel(node), node);
// Update node state if (nodeStates.get(node) == SkillTreeStatus.UNLOCKABLE) setNodeState(node, SkillTreeStatus.UNLOCKED);
nodeStates.compute(node, (key, status) -> status == SkillTreeStatus.UNLOCKABLE ? SkillTreeStatus.UNLOCKED : status); int pointToWithdraw = node.getSkillTreePointsConsumed();
if (skillTreePoints.get(node.getTree().getId()) > 0) {
// Consume skill tree points int pointWithdrawn = Math.min(pointToWithdraw, skillTreePoints.get(node.getTree().getId()));
final AtomicInteger cost = new AtomicInteger(node.getSkillTreePointsConsumed()); withdrawSkillTreePoints(node.getTree().getId(), pointWithdrawn);
skillTreePoints.computeIfPresent(node.getTree().getId(), (key, points) -> { pointToWithdraw -= pointWithdrawn;
final int withdrawn = Math.min(points, cost.get()); }
cost.set(cost.get() - withdrawn); if (pointToWithdraw > 0) withdrawSkillTreePoints("global", pointToWithdraw);
return points <= withdrawn ? null : points - withdrawn; // We unload the nodeStates map (for the skill tree) and reload it completely
}); for (SkillTreeNode node1 : node.getTree().getNodes())
if (cost.get() > 0) withdrawSkillTreePoints("global", cost.get()); nodeStates.remove(node1);
// Reload node states from full skill tree
for (SkillTreeNode node1 : node.getTree().getNodes()) nodeStates.remove(node1);
node.getTree().setupNodeStates(this); 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); return skillTreePoints.getOrDefault(treeId, 0);
} }
public void withdrawSkillTreePoints(@NotNull String treeId, int withdrawn) { public void withdrawSkillTreePoints(String treeId, int withdraw) {
final int cost = Math.max(0, withdrawn); skillTreePoints.put(treeId, skillTreePoints.get(treeId) - withdraw);
skillTreePoints.computeIfPresent(treeId, (ignored, points) -> cost >= points ? null : points - cost);
} }
public void setNodeState(SkillTreeNode node, SkillTreeStatus skillTreeStatus) { public void setNodeState(SkillTreeNode node, SkillTreeStatus skillTreeStatus) {
@ -381,24 +317,15 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return nodeLevels.getOrDefault(node, 0); return nodeLevels.getOrDefault(node, 0);
} }
public void setNodeLevel(@NotNull SkillTreeNode node, int nodeLevel) { public void setNodeLevel(SkillTreeNode node, int nodeLevel) {
nodeLevels.compute(node, (ignored, currentLevelInteger) -> { int delta = (nodeLevel - nodeLevels.getOrDefault(node, 0)) * node.getSkillTreePointsConsumed();
final int currentLevel = currentLevelInteger == null ? 0 : currentLevelInteger; pointSpent.put(node.getTree(), pointSpent.getOrDefault(node.getTree(), 0) + delta);
final int delta = (nodeLevel - currentLevel) * node.getSkillTreePointsConsumed(); nodeLevels.put(node, nodeLevel);
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 resetSkillTree(SkillTree skillTree) { public void resetSkillTree(SkillTree skillTree) {
for (SkillTreeNode node : skillTree.getNodes()) { for (SkillTreeNode node : skillTree.getNodes()) {
node.resetAdvancement(this, true); node.getExperienceTable().reset(this, node);
setNodeLevel(node, 0); setNodeLevel(node, 0);
nodeStates.remove(node); nodeStates.remove(node);
} }
@ -409,6 +336,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return new HashMap<>(nodeStates); return new HashMap<>(nodeStates);
} }
public void clearNodeStates() {
nodeStates.clear();
}
@Override @Override
public Map<String, Integer> getNodeTimesClaimed() { public Map<String, Integer> getNodeTimesClaimed() {
Map<String, Integer> result = new HashMap<>(); Map<String, Integer> result = new HashMap<>();
@ -433,11 +364,11 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/ */
public boolean unlock(Unlockable unlockable) { public boolean unlock(Unlockable unlockable) {
Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot unlock an item unlocked by default"); Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot unlock an item unlocked by default");
final boolean wasLocked = unlockedItems.add(unlockable.getUnlockNamespacedKey());
if (wasLocked) {
unlockable.whenUnlocked(this); 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()))); Bukkit.getScheduler().runTask(MythicLib.plugin, () -> Bukkit.getPluginManager().callEvent(new ItemUnlockedEvent(this, unlockable.getUnlockNamespacedKey())));
}
return wasLocked; return wasLocked;
} }
@ -449,11 +380,11 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/ */
public boolean lock(Unlockable unlockable) { public boolean lock(Unlockable unlockable) {
Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot lock an item unlocked by default"); Validate.isTrue(!unlockable.isUnlockedByDefault(), "Cannot lock an item unlocked by default");
boolean wasUnlocked = unlockedItems.remove(unlockable.getUnlockNamespacedKey());
if (wasUnlocked) {
unlockable.whenLocked(this); 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()))); Bukkit.getScheduler().runTask(MythicLib.plugin, () -> Bukkit.getPluginManager().callEvent(new ItemLockedEvent(this, unlockable.getUnlockNamespacedKey())));
}
return wasUnlocked; return wasUnlocked;
} }
@ -466,7 +397,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
this.unlockedItems.addAll(unlockedItems); this.unlockedItems.addAll(unlockedItems);
} }
@Deprecated
public void resetTimesClaimed() { public void resetTimesClaimed() {
tableItemClaims.clear(); tableItemClaims.clear();
} }
@ -493,7 +423,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
boundSkills.forEach((slot, info) -> info.close()); boundSkills.forEach((slot, info) -> info.close());
// Stop skill casting // Stop skill casting
if (isCasting()) leaveSkillCasting(true); if (isCasting()) leaveSkillCasting();
} }
public List<UUID> getFriends() { public List<UUID> getFriends() {
@ -509,7 +439,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
} }
public long getLastActivity(PlayerActivity activity) { public long getLastActivity(PlayerActivity activity) {
return this.lastActivity.getOrDefault(activity, 0l); return this.lastActivity.getOrDefault(activity, 0L);
} }
public long getActivityTimeOut(PlayerActivity activity) { public long getActivityTimeOut(PlayerActivity activity) {
@ -569,10 +499,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return sum; return sum;
} }
@NotNull @Deprecated
public List<ClassSkill> getUnlockedSkills() { public List<ClassSkill> getUnlockedSkills() {
return getProfess().getSkills().stream() return getProfess().getSkills().stream()
.filter(skill -> hasUnlocked(skill) && hasUnlockedLevel(skill)) .filter((classSkill) -> hasUnlocked(classSkill))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -591,38 +521,22 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return skillTreeReallocationPoints; return skillTreeReallocationPoints;
} }
public int getClaims(@NotNull ExperienceObject object, @NotNull ExperienceItem item) { @Override
final ExperienceTable table = object.getExperienceTable(); public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) {
return getClaims(object.getKey() + "." + table.getId() + "." + item.getId()); return getClaims(object.getKey() + "." + table.getId() + "." + item.getId());
} }
/** public int getClaims(String key) {
* @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) {
return tableItemClaims.getOrDefault(key, 0); return tableItemClaims.getOrDefault(key, 0);
} }
public void setClaims(@NotNull ExperienceObject object, @NotNull ExperienceItem item, int times) { @Override
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
public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) { public void setClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item, int times) {
setClaims(object.getKey() + "." + table.getId() + "." + item.getId(), times); setClaims(object.getKey() + "." + table.getId() + "." + item.getId(), times);
} }
@Deprecated public void setClaims(String key, int times) {
public int getClaims(ExperienceObject object, ExperienceTable table, ExperienceItem item) { tableItemClaims.put(key, times);
return getClaims(object.getKey() + "." + table.getId() + "." + item.getId());
} }
public Map<String, Integer> getItemClaims() { public Map<String, Integer> getItemClaims() {
@ -646,8 +560,9 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void setLevel(int level) { public void setLevel(int level) {
this.level = Math.max(1, level); this.level = Math.max(1, level);
if (isOnline()) { if (isOnline()) {
if (isSynchronized()) getStats().updateStats(); getStats().updateStats();
refreshVanillaExp(); refreshVanillaExp();
} }
} }
@ -805,7 +720,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
setLastActivity(PlayerActivity.FRIEND_REQUEST); setLastActivity(PlayerActivity.FRIEND_REQUEST);
FriendRequest request = new FriendRequest(this, target); 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); MMOCore.plugin.requestManager.registerRequest(request);
} }
@ -835,15 +750,14 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
public void run() { public void run() {
if (!isOnline() || getPlayer().getLocation().getBlockX() != x || getPlayer().getLocation().getBlockY() != y || getPlayer().getLocation().getBlockZ() != z) { 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()); 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); giveStellium(cost, PlayerResourceUpdateEvent.UpdateReason.USE_WAYPOINT);
cancel(); cancel();
return; return;
} }
MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", String.valueOf((warpTime - t) / 20)).send(getPlayer());
if (hasPerm || t++ >= warpTime) { if (hasPerm || t++ >= warpTime) {
getPlayer().teleport(target.getLocation()); getPlayer().teleport(target.getLocation());
getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false)); getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
@ -852,11 +766,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return; 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)); 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); final double r = Math.sin((double) t / warpTime * Math.PI);
for (double j = 0; j < Math.PI * 2; j += Math.PI / 4) 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); }.runTaskTimer(MMOCore.plugin, 0, 1);
} }
@ -921,7 +834,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Experience hologram // Experience hologram
if (hologramLocation != null && isOnline()) 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()); experience = Math.max(0, experience + event.getExperience());
@ -938,15 +851,16 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
level = getLevel() + 1; level = getLevel() + 1;
// Apply class experience table // Apply class experience table
getProfess().updateAdvancement(this, level); if (getProfess().hasExperienceTable())
getProfess().getExperienceTable().claim(this, level, getProfess());
} }
if (level > oldLevel) { if (level > oldLevel) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(this, null, oldLevel, level)); Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(this, null, oldLevel, level));
if (isOnline()) { 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()); MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(getPlayer());
new SmallParticleEffect(getPlayer(), VParticle.INSTANT_EFFECT.get()); new SmallParticleEffect(getPlayer(), Particle.SPELL_INSTANT);
} }
getStats().updateStats(); getStats().updateStats();
} }
@ -1033,7 +947,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
stellium = Math.max(0, Math.min(stellium + event.getAmount(), max)); stellium = Math.max(0, Math.min(stellium + event.getAmount(), max));
} }
@Deprecated
@Override @Override
public double getHealth() { public double getHealth() {
return isOnline() ? getPlayer().getHealth() : health; return isOnline() ? getPlayer().getHealth() : health;
@ -1053,10 +966,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return stellium; return stellium;
} }
public double getCachedHealth() {
return health;
}
public PlayerStats getStats() { public PlayerStats getStats() {
return playerStats; return playerStats;
} }
@ -1097,20 +1006,21 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated @Deprecated
public boolean setSkillCasting(@NotNull SkillCastingInstance skillCasting) { public boolean setSkillCasting(@NotNull SkillCastingInstance skillCasting) {
Validate.isTrue(!isCasting(), "Player already in casting mode");
return setSkillCasting(); return setSkillCasting();
} }
/** /**
* @return If the PlayerEnterCastingModeEvent successfully put the player * @return true if the PlayerEnterCastingModeEvent successfully put the player into casting mode, otherwise if the event is cancelled, returns false.
* 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() { public boolean setSkillCasting() {
Validate.isTrue(!isCasting(), "Player already in casting mode"); Validate.isTrue(!isCasting(), "Player already in casting mode");
PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(this); PlayerEnterCastingModeEvent event = new PlayerEnterCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false; if (event.isCancelled()) return false;
this.skillCasting = SkillCastingMode.getCurrent().newInstance(this); this.skillCasting = SkillCastingMode.getCurrent().newInstance(this);
setLastActivity(PlayerActivity.ENTER_CASTING);
return true; return true;
} }
@ -1120,45 +1030,59 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
} }
/** /**
* @return If player successfully left skill casting i.e the Bukkit * API Method to leave casting mode and fire the PlayerExitCastingModeEvent
* event has not been cancelled *
* @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() { public boolean leaveSkillCasting() {
return leaveSkillCasting(false); return leaveSkillCasting(false);
} }
/** /**
* @param skipEvent Skip firing the exit event * @param skipEvent Skip Firing the PlayerExitCastingModeEvent
* @return If player successfully left skill casting i.e the Bukkit * @return true if the PlayerExitCastingModeEvent is not cancelled, or if the event is skipped.
* event has not been cancelled
*/ */
public boolean leaveSkillCasting(boolean skipEvent) { public boolean leaveSkillCasting(boolean skipEvent) {
Validate.isTrue(isCasting(), "Player not in casting mode"); Validate.isTrue(isCasting(), "Player not in casting mode");
if (!skipEvent) { if (!skipEvent) {
PlayerExitCastingModeEvent event = new PlayerExitCastingModeEvent(this); PlayerExitCastingModeEvent event = new PlayerExitCastingModeEvent(getPlayer());
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) return false; if (event.isCancelled()) return false;
} }
skillCasting.close(); skillCasting.close();
this.skillCasting = null; this.skillCasting = null;
setLastActivity(PlayerActivity.EXIT_CASTING);
setLastActivity(PlayerActivity.ACTION_BAR_MESSAGE, 0); // Reset action bar setLastActivity(PlayerActivity.ACTION_BAR_MESSAGE, 0); // Reset action bar
return true; return true;
} }
public void displayActionBar(@NotNull String message) { /**
displayActionBar(message, false); * @return true if the "skill-casting.timeout" integer (second) is less than the most recent event beteen CAST_SKILL and ENTER_CASTING, it chooses the most recent one as its comparison. This is used for the timeout of casting. Returns false if the value is 0 or if the player is not casting.
*/
public boolean isCastingTimeoutExpired() {
if (MMOCore.plugin.configManager.castingTimeoutTime <= 0) return false;
if (!isCasting()) return false;
long lastSkillCastTime = getLastActivity(PlayerActivity.CAST_SKILL);
long lastEnterCastingTime = getLastActivity(PlayerActivity.ENTER_CASTING);
// If the player is in casting mode but has not yet cast a skill, use the enter casting time
if (lastSkillCastTime == 0L)
lastSkillCastTime = lastEnterCastingTime;
long lastActivityTime = Math.max(lastSkillCastTime, lastEnterCastingTime);
long timeSinceLastActivity = System.currentTimeMillis() - lastActivityTime;
long castingTimeoutMillis = MMOCore.plugin.configManager.castingTimeoutTime * 1000L;
return timeSinceLastActivity > castingTimeoutMillis;
} }
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); setLastActivity(PlayerActivity.ACTION_BAR_MESSAGE);
if (raw) MythicLib.plugin.getVersion().getWrapper().sendActionBarRaw(getPlayer(), message); getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
else getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
} }
@Deprecated @Deprecated
@ -1168,7 +1092,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Deprecated @Deprecated
public void setAttribute(String id, int value) { public void setAttribute(String id, int value) {
attributes.getInstance(id).setBase(value); attributes.setBaseAttribute(id, value);
} }
@Override @Override
@ -1254,7 +1178,6 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
// Clear bound skills // Clear bound skills
boundSkills.forEach((slot, info) -> info.close()); boundSkills.forEach((slot, info) -> info.close());
boundSkills.clear(); boundSkills.clear();
applyTemporaryTriggers();
// Update stats // Update stats
if (isOnline()) getStats().updateStats(); if (isOnline()) getStats().updateStats();
@ -1266,8 +1189,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
@Nullable @Nullable
public ClassSkill getBoundSkill(int slot) { public ClassSkill getBoundSkill(int slot) {
final BoundSkillInfo found = boundSkills.get(slot); return boundSkills.containsKey(slot) ? boundSkills.get(slot).getClassSkill() : null;
return found != null ? found.getClassSkill() : null;
} }
@Deprecated @Deprecated
@ -1283,39 +1205,24 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
*/ */
public void bindSkill(int slot, @NotNull ClassSkill skill) { public void bindSkill(int slot, @NotNull ClassSkill skill) {
Validate.notNull(skill, "Skill cannot be null"); 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 (slot >= 0) {
if (skill.isPermanent()) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Attempted to bind permanent skill " + skill.getSkill().getName() + " to player " + getUniqueId());
return;
}
// Unbinds the previous skill (important for passive skills) // Unbinds the previous skill (important for passive skills)
unbindSkill(slot); unbindSkill(slot);
final SkillSlot skillSlot = getProfess().getSkillSlot(slot); final SkillSlot skillSlot = getProfess().getSkillSlot(slot);
boundSkills.put(slot, new BoundSkillInfo(skillSlot, skill, this)); boundSkills.put(slot, new BoundSkillInfo(skillSlot, skill, this));
} }
}
@Nullable public void unbindSkill(int slot) {
public BoundSkillInfo unbindSkill(int slot) {
final @Nullable BoundSkillInfo boundSkillInfo = boundSkills.remove(slot); final @Nullable BoundSkillInfo boundSkillInfo = boundSkills.remove(slot);
if (boundSkillInfo != null) boundSkillInfo.close(); if (boundSkillInfo != null) boundSkillInfo.close();
return boundSkillInfo;
} }
@NotNull public List<ClassSkill> getBoundSkills() {
public Map<Integer, BoundSkillInfo> getBoundSkills() { return boundSkills.values().stream().map(BoundSkillInfo::getClassSkill).collect(Collectors.toList());
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;
} }
@NotNull @NotNull
@ -1363,16 +1270,12 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
return getMMOPlayerData().hashCode(); return getMMOPlayerData().hashCode();
} }
public static PlayerData get(@NotNull MMOPlayerData playerData) { public static PlayerData get(OfflinePlayer player) {
return get(playerData.getPlayer());
}
public static PlayerData get(@NotNull OfflinePlayer player) {
return get(player.getUniqueId()); return get(player.getUniqueId());
} }
public static PlayerData get(@NotNull UUID uuid) { public static PlayerData get(UUID uuid) {
return MMOCore.plugin.playerDataManager.get(uuid); return MMOCore.plugin.dataProvider.getDataManager().get(uuid);
} }
/** /**
@ -1404,10 +1307,10 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD
* @return If player data for that player is loaded * @return If player data for that player is loaded
*/ */
public static boolean has(UUID uuid) { public static boolean has(UUID uuid) {
return MMOCore.plugin.playerDataManager.isLoaded(uuid); return MMOCore.plugin.dataProvider.getDataManager().isLoaded(uuid);
} }
public static Collection<PlayerData> getAll() { 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; 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.EquipmentSlot;
import io.lumine.mythic.lib.api.player.MMOPlayerData; 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.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType; 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 io.lumine.mythic.lib.util.configobject.ConfigObject;
import net.Indyuce.mmocore.api.player.PlayerData; 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 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) * Flat attribute modifier (simplest modifier you can think about)
*/ */
public AttributeModifier(String key, String attribute, double value) { public AttributeModifier(String key, String attribute, double value) {
super(key, value); this(key, attribute, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER);
this.attribute = attribute;
} }
/** /**
* Attribute modifier given by an external mechanic, like a party buff, item * Attribute modifier given by an external mecanic, like a party buff, item set bonuses,
* set bonuses, skills or abilities... Anything apart from items and armor. * skills or abilities... Anything apart from items and armor.
*/ */
public AttributeModifier(String key, String attribute, double value, ModifierType type) { public AttributeModifier(String key, String attribute, double value, ModifierType type) {
this(key, attribute, value, type, EquipmentSlot.OTHER, ModifierSource.OTHER); 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 * @param source Type of the item granting the stat modifier
*/ */
public AttributeModifier(String key, String attribute, double value, ModifierType type, EquipmentSlot slot, ModifierSource source) { public AttributeModifier(String key, String attribute, double value, ModifierType type, EquipmentSlot slot, ModifierSource source) {
this(UUID.randomUUID(), key, attribute, value, type, slot, source); super(key, 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);
this.attribute = attribute; 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 * @param str The string to be parsed
*/ */
public AttributeModifier(String key, String attribute, String str) { 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; this.attribute = attribute;
} }
public AttributeModifier(ConfigObject object) { 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"); this.attribute = object.getString("attribute");
} }
@ -83,6 +85,14 @@ public class AttributeModifier extends InstanceModifier {
return attribute; return attribute;
} }
public ModifierType getType() {
return type;
}
public double getValue() {
return value;
}
/** /**
* Used to multiply some existing stat modifier by a constant, usually an * Used to multiply some existing stat modifier by a constant, usually an
* integer, for instance when MMOCore party modifiers scale with the * integer, for instance when MMOCore party modifiers scale with the
@ -91,19 +101,24 @@ public class AttributeModifier extends InstanceModifier {
* @param coef The multiplicative constant * @param coef The multiplicative constant
* @return A new instance of StatModifier with modified value * @return A new instance of StatModifier with modified value
*/ */
public AttributeModifier multiply(double coef) { public StatModifier multiply(double coef) {
return new AttributeModifier(getUniqueId(), getKey(), attribute, value * coef, type, getSlot(), getSource()); return new StatModifier(getKey(), attribute, value * coef, type, getSlot(), getSource());
} }
@Override @Override
public void register(MMOPlayerData mmoPlayerData) { public void register(MMOPlayerData mmoPlayerData) {
PlayerData playerData = PlayerData.get(mmoPlayerData); PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId());
playerData.getAttributes().getInstance(attribute).addModifier(this); playerData.getAttributes().getInstance(attribute).addModifier(this);
} }
@Override @Override
public void unregister(MMOPlayerData mmoPlayerData) { public void unregister(MMOPlayerData mmoPlayerData) {
PlayerData playerData = PlayerData.get(mmoPlayerData); PlayerData playerData = PlayerData.get(mmoPlayerData.getUniqueId());
playerData.getAttributes().getInstance(attribute).removeModifier(getKey()); 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

@ -30,7 +30,7 @@ public class MMOCoreAttributeStatHandler extends StatHandler {
@Override @Override
public void runUpdate(StatInstance instance) { public void runUpdate(StatInstance instance) {
try { try {
final PlayerData playerData = PlayerData.get(instance.getMap().getPlayerData()); final PlayerData playerData = MMOCore.plugin.dataProvider.getDataManager().get(instance.getMap().getPlayerData().getUniqueId());
playerData.getAttributes().getInstance(attr).updateStats(); playerData.getAttributes().getInstance(attr).updateStats();
} catch (NullPointerException exception) { } catch (NullPointerException exception) {
// Player data is not loaded yet so there's nothing to update. // Player data is not loaded yet so there's nothing to update.

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ public class AttackEventTrigger implements EventTriggerHandler {
// We don't want players dying by themselves when using an enderpearl. // We don't want players dying by themselves when using an enderpearl.
if (event.getPlayer().equals(event.getEntity())) return; if (event.getPlayer().equals(event.getEntity())) return;
PlayerData player = PlayerData.get(event.getData()); PlayerData player = PlayerData.get(event.getData().getUniqueId());
PlayerClass profess = player.getProfess(); PlayerClass profess = player.getProfess();
for (DamageType type : event.getAttack().getDamage().collectTypes()) { for (DamageType type : event.getAttack().getDamage().collectTypes()) {

View File

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

View File

@ -1,6 +1,6 @@
package net.Indyuce.mmocore.api.player.social; 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.PlayerActivity;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Sound; import org.bukkit.Sound;
@ -21,8 +21,8 @@ public class FriendRequest extends Request {
getCreator().addFriend(getTarget().getUniqueId()); getCreator().addFriend(getTarget().getUniqueId());
getTarget().addFriend(getCreator().getUniqueId()); getTarget().addFriend(getCreator().getUniqueId());
if (getCreator().isOnline()) { if (getCreator().isOnline()) {
ConfigMessage.fromKey("now-friends", "player", getTarget().getPlayer().getName()).send(getCreator().getPlayer()); MMOCore.plugin.configManager.getSimpleMessage("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", 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.modifier.ModifierType;
import io.lumine.mythic.lib.player.skill.PassiveSkill; import io.lumine.mythic.lib.player.skill.PassiveSkill;
import io.lumine.mythic.lib.player.skill.PassiveSkillMap; 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.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.Profession; import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.ClassSkill;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class PlayerStats { public class PlayerStats {
private final PlayerData data; private final PlayerData data;
@ -46,7 +49,7 @@ public class PlayerStats {
} }
public double getStat(String stat) { 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)); 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 * 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 * MythicLib. Must be ran everytime the player levels up or changes class.
* when the plugin reloads.
* <p> * <p>
* Login scripts are a pretty special case of scripts/skills since they are * This is also called when reloading the plugin to make class setup easier,
* not loaded yet when MythicLib triggers them naturally. Therefore, they * see {@link PlayerData#reload()} for more info
* need to be cast as soon as they are loaded into the MMOCore player data.
*
* @param castLoginScripts Should login scripts be cast
*/ */
public synchronized void updateStats(boolean castLoginScripts) { public synchronized void updateStats() {
// Update player stats
for (String stat : MMOCore.plugin.statManager.getRegistered()) { for (String stat : MMOCore.plugin.statManager.getRegistered()) {
final StatInstance instance = getMap().getInstance(stat); final StatInstance instance = getMap().getInstance(stat);
final StatInstance.ModifierPacket packet = instance.newPacket(); final StatInstance.ModifierPacket packet = instance.newPacket();
@ -101,32 +94,24 @@ public class PlayerStats {
packet.runUpdate(); 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(); 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"); skillMap.removeModifiers("MMOCoreClassScript");
for (PassiveSkill script : data.getProfess().getScripts()) for (PassiveSkill script : data.getProfess().getScripts())
if (script.getType() != TriggerType.LOGIN) skillMap.addModifier(script); 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());
}
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.objective; 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.quest.ObjectiveProgress;
import net.Indyuce.mmocore.api.event.CustomBlockMineEvent; import net.Indyuce.mmocore.api.event.CustomBlockMineEvent;
import net.Indyuce.mmocore.api.quest.QuestProgress; import net.Indyuce.mmocore.api.quest.QuestProgress;
@ -43,8 +42,6 @@ public class MineBlockObjective extends Objective {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void a(BlockBreakEvent event) { public void a(BlockBreakEvent event) {
if(!getQuestProgress().getPlayer().isOnline()) return; if(!getQuestProgress().getPlayer().isOnline()) return;
if (UtilityMethods.isFake(event)) return;
if ((!playerPlaced) && event.getBlock().hasMetadata("player_placed")) if ((!playerPlaced) && event.getBlock().hasMetadata("player_placed"))
return; return;
if (event.getPlayer().equals(getQuestProgress().getPlayer().getPlayer()) && event.getBlock().getType() == block) { 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 net.Indyuce.mmocore.skill.RegisteredSkill;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
public class BindSkillTrigger extends Trigger implements Removable { public class BindSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill; private final RegisteredSkill skill;
@ -18,13 +19,14 @@ public class BindSkillTrigger extends Trigger implements Removable {
config.validateKeys("skill", "slot"); config.validateKeys("skill", "slot");
slot = config.getInt("slot"); slot = config.getInt("slot");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill")); skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
} }
@Override @Override
public void apply(PlayerData playerData) { public void apply(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill); final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill);
if (found != null) playerData.bindSkill(slot, found); if (found != null)
playerData.bindSkill(slot, found);
} }
@Override @Override

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.trigger; package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -24,9 +23,7 @@ public class CommandTrigger extends Trigger {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), format(player.getPlayer())); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), format(player.getPlayer()));
} }
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
private String format(Player player) { 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())); 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.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.RegisteredSkill;
import java.util.Objects;
public class LevelUpSkillTrigger extends Trigger implements Removable { public class LevelUpSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill; private final RegisteredSkill skill;
private final int amount; private final int amount;
@ -15,7 +17,7 @@ public class LevelUpSkillTrigger extends Trigger implements Removable {
config.validateKeys("skill", "amount"); config.validateKeys("skill", "amount");
amount = config.getInt("amount"); amount = config.getInt("amount");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill")); skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
} }
@Override @Override

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.api.quest.trigger; package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -23,9 +22,7 @@ public class MessageTrigger extends Trigger {
player.getPlayer().sendMessage(format(player.getPlayer())); player.getPlayer().sendMessage(format(player.getPlayer()));
} }
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
private String format(Player player) { 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())); 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.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable; 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 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.List;
import java.util.stream.Collectors; import java.util.UUID;
public class SkillModifierTrigger extends Trigger implements Removable, Temporary { public class SkillModifierTrigger extends Trigger implements Removable {
private SkillModifier mod; private final SkillModifier mod;
private boolean mutable = true; private final String buffKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount;
public SkillModifierTrigger(MMOLineConfig config) { public SkillModifierTrigger(MMOLineConfig config) {
super(config); super(config);
@ -26,18 +25,16 @@ public class SkillModifierTrigger extends Trigger implements Removable, Temporar
config.validateKeys("modifier"); config.validateKeys("modifier");
config.validateKeys("amount"); config.validateKeys("amount");
final double amount = config.getDouble("amount"); amount = config.getDouble("amount");
final String parameter = config.getString("modifier"); final String skillModifier = config.getString("modifier");
final String formula = config.getString("formula", "true"); final String formula = config.getString("formula", "true");
final ModifierType type = config.contains("type") ? ModifierType.valueOf(UtilityMethods.enumName(config.getString("type"))) : ModifierType.FLAT; 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); mod = new SkillModifier(buffKey, skillModifier, 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());
} }
public List<SkillHandler<?>> getTargetSkills() { public List<SkillHandler<?>> getTargetSkills() {
@ -59,7 +56,6 @@ public class SkillModifierTrigger extends Trigger implements Removable, Temporar
* to a dynamically chosen skill handler. * to a dynamically chosen skill handler.
*/ */
public void apply(PlayerData playerData, SkillHandler<?> skill) { public void apply(PlayerData playerData, SkillHandler<?> skill) {
mutable = false;
mod.register(playerData.getMMOPlayerData(), skill); 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 io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable; 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.apache.commons.lang.Validate;
public class StatTrigger extends Trigger implements Removable, Temporary { import java.util.UUID;
private final StatModifier modifier;
public class StatTrigger extends Trigger implements Removable {
private final StatModifier statModifier;
private final String stat; private final String stat;
private final String modifierKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount; private final double amount;
public StatTrigger(MMOLineConfig config) { public StatTrigger(MMOLineConfig config) {
@ -23,18 +25,20 @@ public class StatTrigger extends Trigger implements Removable, Temporary {
Validate.isTrue(type.equals("FLAT") || type.equals("RELATIVE")); Validate.isTrue(type.equals("FLAT") || type.equals("RELATIVE"));
stat = config.getString("stat"); stat = config.getString("stat");
amount = config.getDouble("amount"); 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 @Override
public void apply(PlayerData player) { public void apply(PlayerData player) {
StatModifier prevModifier = player.getMMOPlayerData().getStatMap().getInstance(stat).getModifier(modifier.getUniqueId()); StatModifier prevModifier = player.getMMOPlayerData().getStatMap().getInstance(stat).getModifier(modifierKey);
if (prevModifier == null) modifier.register(player.getMMOPlayerData()); if (prevModifier == null)
else prevModifier.add(amount).register(player.getMMOPlayerData()); statModifier.register(player.getMMOPlayerData());
else
prevModifier.add(amount).register(player.getMMOPlayerData());
} }
@Override @Override
public void remove(PlayerData playerData) { 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 abstract class Trigger {
public static String STAT_MODIFIER_KEY = "mmocore_trigger"; public static String TRIGGER_PREFIX = "mmocore_trigger";
private final long delay; private final long delay;
public Trigger(MMOLineConfig config) { public Trigger(MMOLineConfig config) {

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.RegisteredSkill;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Objects;
public class UnlockSkillTrigger extends Trigger implements Removable { public class UnlockSkillTrigger extends Trigger implements Removable {
private final RegisteredSkill skill; private final RegisteredSkill skill;
@ -16,18 +17,20 @@ public class UnlockSkillTrigger extends Trigger implements Removable {
super(config); super(config);
config.validateKeys("skill"); config.validateKeys("skill");
skill = MMOCore.plugin.skillManager.getSkillOrThrow(config.getString("skill")); skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(config.getString("skill")));
} }
@Override @Override
public void apply(PlayerData playerData) { public void apply(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill); final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill);
if (found != null) playerData.unlock(found); if (found != null)
playerData.unlock(found);
} }
@Override @Override
public void remove(PlayerData playerData) { public void remove(PlayerData playerData) {
final @Nullable ClassSkill found = playerData.getProfess().getSkill(skill); 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) { public UnlockSlotTrigger(MMOLineConfig config) {
super(config); super(config);
config.validateKeys("slot"); config.validateKeys("slot");
try { try {
slot = Integer.parseInt(config.getString("slot")); slot = Integer.parseInt(config.getString("slot"));
} catch (NumberFormatException exception) { }catch(NumberFormatException e){
throw new IllegalArgumentException("Slot should be a number"); 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 @Override
public void apply(PlayerData player) { 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 @Override
public void remove(PlayerData player) { 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; 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 interface Removable {
public void remove(PlayerData playerData); 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; 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.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.hologram.Hologram;
import io.lumine.mythic.lib.version.VEnchantment; import io.lumine.mythic.lib.version.VersionMaterial;
import net.Indyuce.mmocore.MMOCore; 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.attribute.Attribute;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; 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.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.player.PlayerItemDamageEvent; import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream; import org.bukkit.util.io.BukkitObjectOutputStream;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -35,24 +34,9 @@ public class MMOCoreUtils {
return item != null && item.hasItemMeta() && item.getItemMeta().hasDisplayName(); 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) { public static String displayName(ItemStack item) {
return item.hasItemMeta() && item.getItemMeta().hasDisplayName() ? item.getItemMeta().getDisplayName() 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)); return current == 0 ? maxStat : Math.max(0, Math.min(current, maxStat));
} }
@Deprecated
public static String caseOnWords(String s) { public static String caseOnWords(String s) {
StringBuilder builder = new StringBuilder(s); StringBuilder builder = new StringBuilder(s);
boolean isLastSpace = true; boolean isLastSpace = true;
@ -84,9 +67,32 @@ public class MMOCoreUtils {
return str.toLowerCase().replace("_", "-").replace(" ", "-"); 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) { 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) { private static String repeat(String s, int n) {
@ -110,38 +116,18 @@ public class MMOCoreUtils {
* @param message Message to display * @param message Message to display
*/ */
public static void displayIndicator(Location loc, String message) { public static void displayIndicator(Location loc, String message) {
Hologram holo = Hologram.create(loc, MythicLib.plugin.parseColors(Collections.singletonList(message))); Hologram holo = Hologram.create(loc, Arrays.asList(message));
Bukkit.getScheduler().runTaskLater(MMOCore.plugin, holo::despawn, 20); Bukkit.getScheduler().runTaskLater(MMOCore.plugin, () -> holo.despawn(), 20);
} }
public static boolean isPlayerHead(Material material) { 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) { public static ItemStack readIcon(String string) throws IllegalArgumentException {
meta.addItemFlags(ItemFlag.values()); String[] split = string.split(":");
Material material = Material.valueOf(split[0].toUpperCase().replace("-", "_").replace(" ", "_"));
// Fix 1.20.6+ Paper bug that sucks. HIDE_ATTRIBUTES no longer works when item attribute list is empty return split.length > 1 ? MythicLib.plugin.getVersion().getWrapper().textureItem(material, Integer.parseInt(split[1])) : new ItemStack(material);
// 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 int getWorth(ItemStack[] items) { public static int getWorth(ItemStack[] items) {
@ -257,7 +243,6 @@ public class MMOCoreUtils {
return entities; return entities;
} }
@Deprecated
public static void heal(LivingEntity target, double value) { public static void heal(LivingEntity target, double value) {
double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(); double max = target.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue();
double gain = Math.min(max, target.getHealth() + value) - target.getHealth(); double gain = Math.min(max, target.getHealth() + value) - target.getHealth();
@ -268,8 +253,6 @@ public class MMOCoreUtils {
target.setHealth(target.getHealth() + gain); target.setHealth(target.getHealth() + gain);
} }
private static final Random RANDOM = new Random();
/** /**
* Method used when mining a custom block or fishing, as the corresponding * Method used when mining a custom block or fishing, as the corresponding
* interaction event is cancelled durability is not handled. This method is * 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) { 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()) if (item == null || item.getType().getMaxDurability() == 0 || item.getItemMeta().isUnbreakable())
return; 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); PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, item, damage);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) if (event.isCancelled())
return; return;
ItemMeta meta = item.getItemMeta();
final int newDamage = event.getDamage() + ((Damageable) meta).getDamage(); final int newDamage = event.getDamage() + ((Damageable) meta).getDamage();
if (newDamage >= item.getType().getMaxDurability()) { if (newDamage >= item.getType().getMaxDurability()) {
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1F, 1F); player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1F, 1F);
@ -315,11 +294,4 @@ public class MMOCoreUtils {
public static Location getCenterLocation(Entity entity) { public static Location getCenterLocation(Entity entity) {
return entity.getBoundingBox().getCenter().toLocation(entity.getWorld()); 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; package net.Indyuce.mmocore.api.util.input;
import io.lumine.mythic.lib.MythicLib; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -13,6 +12,8 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.Consumer; import org.bukkit.util.Consumer;
import io.lumine.mythic.lib.MythicLib;
@Deprecated @Deprecated
public class AnvilGUI extends PlayerInput { public class AnvilGUI extends PlayerInput {
private final int containerId; private final int containerId;
@ -23,7 +24,7 @@ public class AnvilGUI extends PlayerInput {
ItemStack paper = new ItemStack(Material.PAPER); ItemStack paper = new ItemStack(Material.PAPER);
ItemMeta paperMeta = paper.getItemMeta(); 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); paper.setItemMeta(paperMeta);
MythicLib.plugin.getVersion().getWrapper().handleInventoryCloseEvent(player); MythicLib.plugin.getVersion().getWrapper().handleInventoryCloseEvent(player);

View File

@ -1,7 +1,6 @@
package net.Indyuce.mmocore.api.util.input; package net.Indyuce.mmocore.api.util.input;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.gui.api.PluginInventory; import net.Indyuce.mmocore.gui.api.PluginInventory;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -38,7 +37,8 @@ public class ChatInput extends PlayerInput {
this.lastOpened = lastOpened; this.lastOpened = lastOpened;
player.closeInventory(); 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 @Override
@ -56,7 +56,7 @@ public class ChatInput extends PlayerInput {
if (event.getMessage().equals("cancel")) { if (event.getMessage().equals("cancel")) {
if (lastOpened != null) if (lastOpened != null)
Bukkit.getScheduler().runTask(MMOCore.plugin, () -> lastOpened.open()); 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 } else
// Run sync // Run sync
Bukkit.getScheduler().runTask(MMOCore.plugin, () -> output(event.getMessage())); Bukkit.getScheduler().runTask(MMOCore.plugin, () -> output(event.getMessage()));

View File

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

View File

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

View File

@ -49,7 +49,7 @@ public class GuildCommand extends RegisteredCommand {
final Request req = MMOCore.plugin.requestManager.getRequest(uuid); final Request req = MMOCore.plugin.requestManager.getRequest(uuid);
Validate.isTrue(!req.isTimedOut() && req instanceof GuildInvite); Validate.isTrue(!req.isTimedOut() && req instanceof GuildInvite);
invite = (GuildInvite) req; invite = (GuildInvite) req;
Validate.isTrue(MMOCore.plugin.nativeGuildManager.isRegistered(invite.getGuild())); Validate.isTrue(MMOCore.plugin.dataProvider.getGuildManager().isRegistered(invite.getGuild()));
} catch (Exception exception) { } catch (Exception exception) {
return true; return true;
} }

View File

@ -3,7 +3,6 @@ package net.Indyuce.mmocore.command;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.comp.flags.CustomFlag; import io.lumine.mythic.lib.comp.flags.CustomFlag;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.command.api.RegisteredCommand; import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand; import net.Indyuce.mmocore.command.api.ToggleableCommand;
@ -27,15 +26,15 @@ public class PvpModeCommand extends RegisteredCommand {
} }
if (!sender.hasPermission("mmocore.pvpmode")) { 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; return false;
} }
final PlayerData playerData = PlayerData.get((Player) sender); final PlayerData playerData = PlayerData.get(((Player) sender).getUniqueId());
// Command cooldown // Command cooldown
if (playerData.getCooldownMap().isOnCooldown(COOLDOWN_KEY)) { 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; return true;
} }
@ -46,12 +45,12 @@ public class PvpModeCommand extends RegisteredCommand {
if (playerData.getCombat().isInPvpMode() && if (playerData.getCombat().isInPvpMode() &&
MythicLib.plugin.getFlags().isFlagAllowed(playerData.getPlayer(), CustomFlag.PVP_MODE)) { MythicLib.plugin.getFlags().isFlagAllowed(playerData.getPlayer(), CustomFlag.PVP_MODE)) {
playerData.getCombat().setInvulnerable(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand); 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()); MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand)).send(playerData.getPlayer());
// Just send message otherwise // Just send message otherwise
} else } 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; return true;
} }
} }

View File

@ -1,22 +1,17 @@
package net.Indyuce.mmocore.command; package net.Indyuce.mmocore.command;
import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.MMOCore; 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.player.PlayerData;
import net.Indyuce.mmocore.api.event.MMOCommandEvent;
import net.Indyuce.mmocore.command.api.RegisteredCommand; import net.Indyuce.mmocore.command.api.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand; import net.Indyuce.mmocore.command.api.ToggleableCommand;
import net.Indyuce.mmocore.manager.InventoryManager; import net.Indyuce.mmocore.manager.InventoryManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.stream.Collectors;
public class SkillTreesCommand extends RegisteredCommand { public class SkillTreesCommand extends RegisteredCommand {
public SkillTreesCommand(ConfigurationSection config) { public SkillTreesCommand(ConfigurationSection config) {
super(config, ToggleableCommand.SKILL_TREES); super(config, ToggleableCommand.SKILL_TREES);
@ -26,52 +21,20 @@ public class SkillTreesCommand extends RegisteredCommand {
public boolean execute(@NotNull CommandSender sender, String s, String[] args) { public boolean execute(@NotNull CommandSender sender, String s, String[] args) {
if (!sender.hasPermission("mmocore.skilltrees")) if (!sender.hasPermission("mmocore.skilltrees"))
return false; return false;
if (!(sender instanceof Player)) if (!(sender instanceof Player player))
return false; return false;
final Player player = (Player) sender;
PlayerData data = PlayerData.get(player); PlayerData data = PlayerData.get(player);
MMOCommandEvent event = new MMOCommandEvent(data, "skilltrees"); MMOCommandEvent event = new MMOCommandEvent(data, "skilltrees");
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) if (event.isCancelled())
return false; return true;
// Default skilltree command
if (args.length == 0) {
if (!MMOCore.plugin.configManager.enableGlobalSkillTreeGUI) {
sender.sendMessage(ChatColor.RED + "Usage: /skilltrees <skilltree_id>");
return false;
}
if (data.getProfess().getSkillTrees().size() != 0) { if (data.getProfess().getSkillTrees().size() != 0) {
InventoryManager.TREE_VIEW.newInventory(data).open(); InventoryManager.TREE_VIEW.newInventory(data).open();
return false;
}
else {
MMOCore.plugin.configManager.getSimpleMessage("no-skill-tree").send(player);
return true; return true;
} else {
ConfigMessage.fromKey("no-skill-tree").send(player);
return false;
}
}
if (args.length == 1) {
if (!MMOCore.plugin.configManager.enableSpecificSkillTreeGUI) {
sender.sendMessage(ChatColor.RED + "Usage: /skilltrees <skilltree-id>");
return false;
}
if (data.getProfess().getSkillTrees()
.stream()
.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();
return true;
} else {
sender.sendMessage(ChatColor.RED + "Your class does not have a skill tree with id: " + args[0]);
return false;
}
} else {
if (MMOCore.plugin.configManager.enableSpecificSkillTreeGUI)
sender.sendMessage(ChatColor.RED + "Usage: /skilltrees <skilltree-id>");
else
sender.sendMessage(ChatColor.RED + "Usage: /skilltrees");
return false;
} }
} }
} }

View File

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

View File

@ -1,8 +1,6 @@
package net.Indyuce.mmocore.command; package net.Indyuce.mmocore.command;
import net.Indyuce.mmocore.MMOCore; 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.RegisteredCommand;
import net.Indyuce.mmocore.command.api.ToggleableCommand; import net.Indyuce.mmocore.command.api.ToggleableCommand;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
@ -13,6 +11,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import net.Indyuce.mmocore.api.eco.Withdraw;
public class WithdrawCommand extends RegisteredCommand { public class WithdrawCommand extends RegisteredCommand {
public WithdrawCommand(ConfigurationSection config) { public WithdrawCommand(ConfigurationSection config) {
super(config, ToggleableCommand.WITHDRAW); super(config, ToggleableCommand.WITHDRAW);
@ -37,7 +37,7 @@ public class WithdrawCommand extends RegisteredCommand {
amount = Integer.parseInt(amountArgument); amount = Integer.parseInt(amountArgument);
Validate.isTrue(amount >= 0); Validate.isTrue(amount >= 0);
} catch (IllegalArgumentException exception) { } 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; return true;
} }
@ -50,14 +50,14 @@ public class WithdrawCommand extends RegisteredCommand {
int left = (int) MMOCore.plugin.economy.getEconomy().getBalance(player) - amount; int left = (int) MMOCore.plugin.economy.getEconomy().getBalance(player) - amount;
if (left < 0) { 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; return true;
} }
MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, amount); MMOCore.plugin.economy.getEconomy().withdrawPlayer(player, amount);
request.withdrawAlgorythm(amount); request.withdrawAlgorythm(amount);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); 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; 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("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-realloc", this, PlayerData::setSkillReallocationPoints, PlayerData::giveSkillReallocationPoints, PlayerData::getSkillReallocationPoints));
addChild(new PointsCommandTreeNode("skill-tree-realloc", this, PlayerData::setSkillTreeReallocationPoints, PlayerData::giveSkillTreeReallocationPoints, PlayerData::getSkillTreeReallocationPoints)); 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()) for (PlayerResource res : PlayerResource.values())
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res)); addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
} }

View File

@ -1,20 +1,20 @@
package net.Indyuce.mmocore.command.rpg.admin; 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.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.player.PlayerData;
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
import net.Indyuce.mmocore.api.player.profess.PlayerClass; 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.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; 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 class ClassCommandTreeNode extends CommandTreeNode {
public ClassCommandTreeNode(CommandTreeNode parent) { public ClassCommandTreeNode(CommandTreeNode parent) {
super(parent, "class"); super(parent, "class");
@ -52,9 +52,9 @@ public class ClassCommandTreeNode extends CommandTreeNode {
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
(data.hasSavedClass(profess) ? data.getClassInfo(profess) (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()) { 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); 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; 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.command.api.CommandTreeNode;
import io.lumine.mythic.lib.data.DataExport;
import io.lumine.mythic.lib.data.sql.SQLDataSource; import io.lumine.mythic.lib.data.sql.SQLDataSource;
import net.Indyuce.mmocore.MMOCore; 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.sql.SQLDataHandler;
import net.Indyuce.mmocore.manager.data.yaml.YAMLPlayerDataHandler;
import org.bukkit.command.CommandSender; 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 * This command allows to transfer data from your actual storage type
@ -18,15 +27,82 @@ public class ExportDataTreeNode extends CommandTreeNode {
super(parent, "exportdata"); 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 @Override
@NotNull
public CommandResult execute(CommandSender sender, String[] strings) { public CommandResult execute(CommandSender sender, String[] strings) {
// Export YAML to SQL if (!MMOCore.plugin.dataProvider.getDataManager().getLoaded().isEmpty()) {
final boolean result = new DataExport<>(MMOCore.plugin.playerDataManager, sender).start( sender.sendMessage("Please make sure no players are logged in when using this command. " +
() -> new YAMLPlayerDataHandler(MMOCore.plugin), "If you are still seeing this message, restart your server and execute this command before any player logs in.");
() -> new SQLDataHandler(new SQLDataSource(MMOCore.plugin))); 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; 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.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.experience.Profession;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttributes;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; 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 class ResetCommandTreeNode extends CommandTreeNode {
public ResetCommandTreeNode(CommandTreeNode parent) { public ResetCommandTreeNode(CommandTreeNode parent) {
super(parent, "reset"); super(parent, "reset");
addChild(new ResetClassesCommandTreeNode(this));
addChild(new ResetLevelsCommandTreeNode(this)); addChild(new ResetLevelsCommandTreeNode(this));
addChild(new ResetSkillsCommandTreeNode(this)); addChild(new ResetSkillsCommandTreeNode(this));
addChild(new ResetQuestsCommandTreeNode(this)); addChild(new ResetAllCommandTreeNode(this));
addChild(new ResetAttributesCommandTreeNode(this)); addChild(new ResetAttributesCommandTreeNode(this));
addChild(new ResetWaypointsCommandTreeNode(this)); addChild(new ResetWaypointsCommandTreeNode(this));
addChild(new ResetSkillTreesCommandTreeNode(this)); addChild(new ResetSkillTreesCommandTreeNode(this));
addChild(new ResetAllCommandTreeNode(this));
} }
@Override @Override
@ -44,7 +40,8 @@ public class ResetCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -52,25 +49,34 @@ public class ResetCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
final boolean givePoints = args.length > 4 && args[4].equalsIgnoreCase("-reallocate");
PlayerData data = PlayerData.get(player); PlayerData data = PlayerData.get(player);
ResetClassesCommandTreeNode.resetClasses(data); MMOCore.plugin.dataProvider.getDataManager().getDefaultData().apply(data);
ResetLevelsCommandTreeNode.resetLevels(data); data.setExperience(0);
ResetSkillsCommandTreeNode.resetSkills(data); for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
ResetQuestsCommandTreeNode.resetQuests(data); data.getCollectionSkills().setExperience(profession, 0);
ResetAttributesCommandTreeNode.resetAttributes(data, givePoints); data.getCollectionSkills().setLevel(profession, 0);
ResetWaypointsCommandTreeNode.resetWaypoints(data); }
ResetSkillTreesCommandTreeNode.resetSkillTrees(data); MMOCore.plugin.classManager.getAll().forEach(data::unloadClassInfo);
// Reset times-claimed not being properly emptied otherwise data.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
data.getItemClaims().clear(); data.mapSkillLevels().forEach((skill, level) -> data.resetSkillLevel(skill));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s data was successfully reset."); 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; return CommandResult.SUCCESS;
} }
} }
}
class ResetWaypointsCommandTreeNode extends CommandTreeNode { public static class ResetWaypointsCommandTreeNode extends CommandTreeNode {
public ResetWaypointsCommandTreeNode(CommandTreeNode parent) { public ResetWaypointsCommandTreeNode(CommandTreeNode parent) {
super(parent, "waypoints"); super(parent, "waypoints");
@ -79,7 +85,8 @@ class ResetWaypointsCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -87,17 +94,13 @@ class ResetWaypointsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
resetWaypoints(PlayerData.get(player)); PlayerData data = PlayerData.get(player);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s waypoints were successfully reset."); data.getWaypoints().clear();
return CommandResult.SUCCESS; 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) { public ResetQuestsCommandTreeNode(CommandTreeNode parent) {
super(parent, "quests"); super(parent, "quests");
@ -106,7 +109,8 @@ class ResetQuestsCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -114,18 +118,14 @@ class ResetQuestsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
resetQuests(PlayerData.get(player)); PlayerData data = 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) {
data.getQuestData().resetFinishedQuests(); data.getQuestData().resetFinishedQuests();
data.getQuestData().start(null); data.getQuestData().start(null);
return CommandResult.SUCCESS;
} }
} }
class ResetSkillsCommandTreeNode extends CommandTreeNode { public static class ResetSkillsCommandTreeNode extends CommandTreeNode {
public ResetSkillsCommandTreeNode(CommandTreeNode parent) { public ResetSkillsCommandTreeNode(CommandTreeNode parent) {
super(parent, "skills"); super(parent, "skills");
@ -134,7 +134,8 @@ class ResetSkillsCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -142,19 +143,18 @@ class ResetSkillsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
resetSkills(PlayerData.get(player)); PlayerData data = PlayerData.get(player);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill data was successfully reset."); 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; 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) { public ResetSkillTreesCommandTreeNode(CommandTreeNode parent) {
super(parent, "skill-trees"); super(parent, "skill-trees");
@ -163,7 +163,8 @@ class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -171,18 +172,16 @@ class ResetSkillTreesCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
resetSkillTrees(PlayerData.get(player)); PlayerData data = PlayerData.get(player);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s skill-tree data was successfully reset."); 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; 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) { public ResetAttributesCommandTreeNode(CommandTreeNode parent) {
super(parent, "attributes"); super(parent, "attributes");
@ -192,7 +191,8 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -200,16 +200,12 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
final boolean givePoints = args.length > 4 && args[4].equalsIgnoreCase("-reallocate"); PlayerData data = PlayerData.get(player);
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;
}
static void resetAttributes(@NotNull PlayerData data, boolean givePoints) { /*
* force reallocating of player attribute points
// Give back attribute points */
if (givePoints) { if (args.length > 4 && args[4].equalsIgnoreCase("-reallocate")) {
int points = 0; int points = 0;
for (PlayerAttributes.AttributeInstance ins : data.getAttributes().getInstances()) { for (PlayerAttributes.AttributeInstance ins : data.getAttributes().getInstances()) {
@ -218,17 +214,19 @@ class ResetAttributesCommandTreeNode extends CommandTreeNode {
} }
data.giveAttributePoints(points); 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()) { data.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
attribute.resetAdvancement(data, true); CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
data.getAttributes().getInstance(attribute).setBase(0); 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) { public ResetLevelsCommandTreeNode(CommandTreeNode parent) {
super(parent, "levels"); super(parent, "levels");
@ -237,7 +235,8 @@ class ResetLevelsCommandTreeNode extends CommandTreeNode {
@Override @Override
public CommandResult execute(CommandSender sender, String[] args) { 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]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { if (player == null) {
@ -245,52 +244,19 @@ class ResetLevelsCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
resetLevels(PlayerData.get(player)); PlayerData data = PlayerData.get(player);
CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET, ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s levels were successfully reset."); data.setLevel(MMOCore.plugin.dataProvider.getDataManager().getDefaultData().getLevel());
return CommandResult.SUCCESS;
}
static void resetLevels(@NotNull PlayerData data) {
// Class
data.setLevel(MMOCore.plugin.playerDataManager.getDefaultData().getLevel());
data.setExperience(0); data.setExperience(0);
data.getProfess().resetAdvancement(data, true);
// Professions
for (Profession profession : MMOCore.plugin.professionManager.getAll()) { for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
data.getCollectionSkills().setExperience(profession, 0); data.getCollectionSkills().setExperience(profession, 0);
data.getCollectionSkills().setLevel(profession, 0); data.getCollectionSkills().setLevel(profession, 0);
profession.resetAdvancement(data, true); profession.getExperienceTable().reset(data, profession);
}
}
} }
class ResetClassesCommandTreeNode extends CommandTreeNode { CommandVerbose.verbose(sender, CommandVerbose.CommandType.RESET,
public ResetClassesCommandTreeNode(CommandTreeNode parent) { ChatColor.GOLD + player.getName() + ChatColor.YELLOW + "'s levels were succesfully reset.");
super(parent, "classes");
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; 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; 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; return CommandResult.SUCCESS;
} }

View File

@ -68,6 +68,7 @@ public class SkillCommandTreeNode extends CommandTreeNode {
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
int amount; int amount;
try { try {
amount = Integer.parseInt(args[5]); amount = Integer.parseInt(args[5]);
@ -77,7 +78,7 @@ public class SkillCommandTreeNode extends CommandTreeNode {
} }
int value = change.apply(playerData.getSkillLevel(skill), amount); int value = change.apply(playerData.getSkillLevel(skill), amount);
playerData.setSkillLevel(skill, value); 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() + "."); + " is now level " + ChatColor.GOLD + value + ChatColor.YELLOW + " for " + skill.getName() + ".");
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} }
@ -100,31 +101,31 @@ public class SkillCommandTreeNode extends CommandTreeNode {
return CommandResult.THROW_USAGE; return CommandResult.THROW_USAGE;
Player player = Bukkit.getPlayer(args[3]); Player player = Bukkit.getPlayer(args[3]);
if (player == null) { 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; return CommandResult.FAILURE;
} }
PlayerData playerData = PlayerData.get(player); PlayerData playerData = PlayerData.get(player);
ClassSkill skill = playerData.getProfess().getSkill(args[4]); ClassSkill skill = playerData.getProfess().getSkill(args[4]);
if (skill == null) { 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; return CommandResult.FAILURE;
} }
if (lock) { if (lock) {
if (!playerData.hasUnlocked(skill)) { 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; return CommandResult.SUCCESS;
} }
playerData.lock(skill); playerData.lock(skill);
} else { } else {
if (playerData.hasUnlocked(skill)) { 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; return CommandResult.SUCCESS;
} }
playerData.unlock(skill); 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; 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 io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.skill.binding.SkillSlot;
import net.Indyuce.mmocore.command.api.CommandVerbose; import net.Indyuce.mmocore.command.api.CommandVerbose;
import net.Indyuce.mmocore.skill.ClassSkill; 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."); sender.sendMessage(ChatColor.RED + "The slot can't be negative.");
return CommandResult.FAILURE; 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); SkillSlot skillSlot = playerData.getProfess().getSkillSlot(slot);
if(skillSlot.isUnlockedByDefault()){ if(skillSlot.isUnlockedByDefault()){
sender.sendMessage(ChatColor.RED + "You can't lock a skill that is unlocked by default."); 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); 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; return CommandResult.SUCCESS;
} }
} }
@ -114,7 +117,7 @@ public class SlotCommandTreeNode extends CommandTreeNode {
} }
playerData.bindSkill(slot, skill); 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; return CommandResult.SUCCESS;
} }
} }
@ -144,10 +147,11 @@ public class SlotCommandTreeNode extends CommandTreeNode {
sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number."); sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number.");
return CommandResult.FAILURE; return CommandResult.FAILURE;
} }
final BoundSkillInfo found = playerData.unbindSkill(slot); String skill = playerData.hasSkillBound(slot) ? playerData.getBoundSkill(slot).getSkill().getHandler().getId() : "none";
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.YELLOW + (found != null ? if (playerData.hasSkillBound(slot))
"Skill " + ChatColor.GOLD + found.getClassSkill().getSkill().getName() + ChatColor.YELLOW + " was taken off the slot " + ChatColor.GOLD + slot : playerData.unbindSkill(slot);
"Could not find skill at slot " + ChatColor.GOLD + slot));
CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill + " has been unbounded from the slot " + slot);
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} }
} }

View File

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

View File

@ -33,7 +33,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode {
sender.sendMessage("Stat Modifiers (" + instance.getKeys().size() + "):"); sender.sendMessage("Stat Modifiers (" + instance.getKeys().size() + "):");
for (String key : instance.getKeys()) { for (String key : instance.getKeys()) {
StatModifier mod = instance.getModifier(key); 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; 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.config.MythicLineConfig;
import io.lumine.mythic.api.drops.DropMetadata; import io.lumine.mythic.api.drops.DropMetadata;
import io.lumine.mythic.api.drops.IItemDrop; 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.core.drops.Drop;
import net.Indyuce.mmocore.util.item.CurrencyItemBuilder; import net.Indyuce.mmocore.util.item.CurrencyItemBuilder;
@ -27,8 +27,7 @@ public class CurrencyItemDrop extends Drop implements IItemDrop {
@Override @Override
public AbstractItemStack getDrop(DropMetadata dropMetadata, double v) { public AbstractItemStack getDrop(DropMetadata dropMetadata, double v) {
// Not great wrt to performance. Should build the item like MM does return new BukkitItemStack(new CurrencyItemBuilder(key, random(minw, maxw)).build());
return BukkitAdapter.adapt(new CurrencyItemBuilder(key, random(minw, maxw)).build());
} }
private int random(int a, int b) { 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.config.MythicLineConfig;
import io.lumine.mythic.api.drops.DropMetadata; import io.lumine.mythic.api.drops.DropMetadata;
import io.lumine.mythic.api.drops.IItemDrop; 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.core.drops.Drop;
import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem; 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))); 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 new BukkitItemStack(nbt.toItem());
return BukkitAdapter.adapt(nbt.toItem());
} }
private ItemStack setAmount(ItemStack item, int amount) { private ItemStack setAmount(ItemStack item, int amount) {

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.comp.placeholder; package net.Indyuce.mmocore.comp.placeholder;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
@ -8,9 +7,7 @@ import io.lumine.mythic.lib.MythicLib;
public class DefaultParser implements PlaceholderParser { public class DefaultParser implements PlaceholderParser {
@Override @Override
@BackwardsCompatibility(version = "1.12-SNAPSHOT")
public String parse(OfflinePlayer player, String string) { 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())); 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.PlayerProfessions;
import net.Indyuce.mmocore.experience.Profession; import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.party.AbstractParty; import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.skill.CastableSkill;
import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.RegisteredSkill;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@ -60,11 +58,10 @@ public class RPGPlaceholders extends PlaceholderExpansion {
public String onRequest(OfflinePlayer player, String identifier) { public String onRequest(OfflinePlayer player, String identifier) {
if (!PlayerData.has(player.getUniqueId())) if (!PlayerData.has(player.getUniqueId()))
return null; return null;
final PlayerData playerData = PlayerData.get(player);
PlayerData playerData = PlayerData.get(player);
if (identifier.equals("mana_icon")) if (identifier.equals("mana_icon"))
return playerData.getProfess().getManaDisplay().getIcon(); return playerData.getProfess().getManaDisplay().getIcon();
if (identifier.equals("mana_name")) if (identifier.equals("mana_name"))
return playerData.getProfess().getManaDisplay().getName(); return playerData.getProfess().getManaDisplay().getName();
@ -73,49 +70,24 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.startsWith("skill_level_")) { else if (identifier.startsWith("skill_level_")) {
String id = identifier.substring(12); 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)); return String.valueOf(playerData.getSkillLevel(skill));
} } 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];
* Given a skill slot number (integer) and a parameter name, String skillId = ids[1];
* return the player's value of that skill parameter from that RegisteredSkill skill = Objects.requireNonNull(MMOCore.plugin.skillManager.getSkill(skillId), "Could not find skill with ID '" + skillId + "'");
* specific skill slot. ClassSkill classSkill = playerData.getProfess().getSkill(skill);
*/ double value = classSkill.toCastable(playerData).getParameter(parameterId);
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);
return MythicLib.plugin.getMMOConfig().decimal.format(value); return MythicLib.plugin.getMMOConfig().decimal.format(value);
} } else if (identifier.startsWith("attribute_points_spent_")) {
String attributeId = identifier.substring(31);
// Returns a player's value of a skill parameter. PlayerAttributes.AttributeInstance attributeInstance = Objects.requireNonNull(playerData.getAttributes().getInstance(attributeId), "Could not find attribute with ID '" + attributeId + "'");
else if (identifier.startsWith("skill_modifier_") || identifier.startsWith("skill_parameter_")) { return String.valueOf(attributeInstance.getSpent());
final String[] ids = identifier.substring(identifier.startsWith("skill_modifier_") ? 15 : 16).split(":"); } else if (identifier.equals("level_percent")) {
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")) {
double current = playerData.getExperience(), next = playerData.getLevelUpExperience(); double current = playerData.getExperience(), next = playerData.getLevelUpExperience();
return MythicLib.plugin.getMMOConfig().decimal.format(current / next * 100); 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()); return StatManager.format("MAX_HEALTH", player.getPlayer().getHealth());
else if (identifier.equals("max_health")) else if (identifier.equals("max_health"))
@ -155,42 +127,11 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.startsWith("since_last_hit")) else if (identifier.startsWith("since_last_hit"))
return playerData.isInCombat() ? MythicLib.plugin.getMMOConfig().decimal.format((System.currentTimeMillis() - playerData.getCombat().getLastHit()) / 1000.) : "-1"; 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_")) { else if (identifier.startsWith("bound_")) {
final int slot = Math.max(1, Integer.parseInt(identifier.substring(6))); int slot = Math.max(0, Integer.parseInt(identifier.substring(6)));
final ClassSkill skill = playerData.getBoundSkill(slot); return playerData.hasSkillBound(slot) ? playerData.getBoundSkill(slot).getSkill().getName()
if (skill == null) return MMOCore.plugin.configManager.noSkillBoundPlaceholder; : MMOCore.plugin.configManager.noSkillBoundPlaceholder;
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_")) {
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;
} else if (identifier.startsWith("profession_experience_")) } else if (identifier.startsWith("profession_experience_"))
return MythicLib.plugin.getMMOConfig().decimal.format( return MythicLib.plugin.getMMOConfig().decimal.format(
playerData.getCollectionSkills().getExperience(identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase())); playerData.getCollectionSkills().getExperience(identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase()));

View File

@ -1,23 +1,22 @@
package net.Indyuce.mmocore.comp.profile; package net.Indyuce.mmocore.comp.profile;
import fr.phoenixdevt.profiles.ProfileDataModule; import fr.phoenixdevt.profile.ProfileDataModule;
import fr.phoenixdevt.profiles.ProfileProvider; import fr.phoenixdevt.profile.ProfileProvider;
import fr.phoenixdevt.profiles.event.ProfileCreateEvent; import fr.phoenixdevt.profile.event.ProfileCreateEvent;
import fr.phoenixdevt.profiles.event.ProfileRemoveEvent; import fr.phoenixdevt.profile.event.ProfileRemoveEvent;
import fr.phoenixdevt.profiles.event.ProfileSelectEvent; import fr.phoenixdevt.profile.event.ProfileSelectEvent;
import fr.phoenixdevt.profiles.event.ProfileUnloadEvent; import fr.phoenixdevt.profile.event.ProfileUnloadEvent;
import io.lumine.mythic.lib.MythicLib; import fr.phoenixdevt.profile.placeholder.PlaceholderRequest;
import io.lumine.mythic.lib.api.event.SynchronizedDataLoadEvent; import io.lumine.mythic.lib.api.event.SynchronizedDataLoadEvent;
import io.lumine.mythic.lib.comp.profile.ProfileMode;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.manager.InventoryManager; import net.Indyuce.mmocore.manager.InventoryManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class ForceClassProfileDataModule implements ProfileDataModule { public class ForceClassProfileDataModule implements ProfileDataModule, Listener {
public ForceClassProfileDataModule() { public ForceClassProfileDataModule() {
final ProfileProvider<?> provider = Bukkit.getServicesManager().getRegistration(ProfileProvider.class).getProvider(); final ProfileProvider<?> provider = Bukkit.getServicesManager().getRegistration(ProfileProvider.class).getProvider();
provider.registerModule(this); provider.registerModule(this);
@ -28,24 +27,27 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
return MMOCore.plugin; return MMOCore.plugin;
} }
@Override
public boolean hasPlaceholders() {
return false;
}
@Override @Override
public String getIdentifier() { public String getIdentifier() {
return "mmocore_force_class"; return "mmocore_force_class";
} }
@Override
public void processPlaceholderRequest(PlaceholderRequest placeholderRequest) {
throw new RuntimeException("Not supported");
}
/** /**
* Force class before profile creation * Force class before profile creation
*/ */
@EventHandler @EventHandler
public void onProfileCreate(ProfileCreateEvent event) { public void onProfileCreate(ProfileCreateEvent event) {
final PlayerData playerData = PlayerData.get(event.getPlayerData().getUniqueId());
// Proxy-based profiles
if (MythicLib.plugin.getProfileMode() == ProfileMode.PROXY) {
event.validate(this);
return;
}
final PlayerData playerData = PlayerData.get(event.getPlayerData().getPlayer());
InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open(); InventoryManager.CLASS_SELECT.newInventory(playerData, () -> event.validate(this)).open();
} }
@ -56,16 +58,6 @@ public class ForceClassProfileDataModule implements ProfileDataModule {
public void onDataLoad(SynchronizedDataLoadEvent event) { public void onDataLoad(SynchronizedDataLoadEvent event) {
if (event.getManager().getOwningPlugin().equals(MMOCore.plugin)) { if (event.getManager().getOwningPlugin().equals(MMOCore.plugin)) {
final PlayerData playerData = (PlayerData) event.getHolder(); final PlayerData playerData = (PlayerData) event.getHolder();
// Proxy-based profiles
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();
return;
}
final ProfileSelectEvent event1 = (ProfileSelectEvent) event.getProfileEvent(); final ProfileSelectEvent event1 = (ProfileSelectEvent) event.getProfileEvent();
// Validate if necessary // Validate if necessary

View File

@ -1,10 +1,9 @@
package net.Indyuce.mmocore.comp.profile; package net.Indyuce.mmocore.comp.profile;
import fr.phoenixdevt.profiles.ProfileDataModule; import fr.phoenixdevt.profile.ProfileDataModule;
import fr.phoenixdevt.profiles.event.ProfileCreateEvent; import fr.phoenixdevt.profile.event.ProfileCreateEvent;
import fr.phoenixdevt.profiles.event.ProfileRemoveEvent; import fr.phoenixdevt.profile.event.ProfileRemoveEvent;
import fr.phoenixdevt.profiles.placeholder.PlaceholderProcessor; import fr.phoenixdevt.profile.placeholder.PlaceholderRequest;
import fr.phoenixdevt.profiles.placeholder.PlaceholderRequest;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData; import io.lumine.mythic.lib.api.player.MMOPlayerData;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
@ -12,29 +11,30 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.experience.Profession; import net.Indyuce.mmocore.experience.Profession;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class MMOCoreProfileDataModule implements ProfileDataModule, PlaceholderProcessor { public class MMOCoreProfileDataModule implements ProfileDataModule, Listener {
@Override @Override
public JavaPlugin getOwningPlugin() { public JavaPlugin getOwningPlugin() {
return MMOCore.plugin; return MMOCore.plugin;
} }
@Override
public boolean hasPlaceholders() {
return true;
}
@Override @Override
public String getIdentifier() { public String getIdentifier() {
return "mmocore"; return "mmocore";
} }
@Override
public ProfileDataModule getDataModule() {
return this;
}
@Override @Override
public void processPlaceholderRequest(PlaceholderRequest placeholderRequest) { public void processPlaceholderRequest(PlaceholderRequest placeholderRequest) {
final PlayerData fictiveData = new PlayerData(new MMOPlayerData(placeholderRequest.getProfile().getUniqueId())); final PlayerData fictiveData = new PlayerData(new MMOPlayerData(placeholderRequest.getProfile().getUniqueId()));
MMOCore.plugin.playerDataManager.loadData(fictiveData).thenRun(() -> { MMOCore.plugin.playerDataManager.getDataHandler().loadData(fictiveData).thenRun(() -> {
placeholderRequest.addPlaceholder("class", fictiveData.getProfess().getName()); placeholderRequest.addPlaceholder("class", fictiveData.getProfess().getName());
placeholderRequest.addPlaceholder("level", fictiveData.getLevel()); placeholderRequest.addPlaceholder("level", fictiveData.getLevel());

View File

@ -10,7 +10,6 @@ import com.sk89q.worldguard.session.MoveType;
import com.sk89q.worldguard.session.Session; import com.sk89q.worldguard.session.Session;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
public class PvPFlagHandler extends MMOCoreFlagHandler { public class PvPFlagHandler extends MMOCoreFlagHandler {
@ -51,7 +50,7 @@ public class PvPFlagHandler extends MMOCoreFlagHandler {
// Send message // Send message
if (canSendMessage()) { if (canSendMessage()) {
lastMessage = System.currentTimeMillis(); 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()); 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.CustomFlag;
import io.lumine.mythic.lib.comp.flags.WorldGuardFlags; import io.lumine.mythic.lib.comp.flags.WorldGuardFlags;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.command.PvpModeCommand; import net.Indyuce.mmocore.command.PvpModeCommand;
import java.util.Objects; import java.util.Objects;
@ -65,7 +64,7 @@ public class PvPModeHandler extends MMOCoreFlagHandler {
final boolean pvpEnabled = playerData.getCombat().isInPvpMode() && !playerData.getCombat().canQuitPvpMode() && pvpFlag; final boolean pvpEnabled = playerData.getCombat().isInPvpMode() && !playerData.getCombat().canQuitPvpMode() && pvpFlag;
lastMessage = System.currentTimeMillis(); lastMessage = System.currentTimeMillis();
final double remaining = (playerData.getCombat().getLastHit() + MMOCore.plugin.configManager.pvpModeCombatTimeout * 1000.0D - System.currentTimeMillis()) / 1000.0D; 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()); (MythicLib.plugin.getMMOConfig()).decimal.format(remaining)).send(playerData.getPlayer());
} }
} else if (newPvpMode && !lastPvpMode) { } else if (newPvpMode && !lastPvpMode) {
@ -81,7 +80,7 @@ public class PvPModeHandler extends MMOCoreFlagHandler {
// Send message // Send message
if (canSendMessage()) { if (canSendMessage()) {
lastMessage = System.currentTimeMillis(); 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()); 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.UtilityMethods;
import io.lumine.mythic.lib.comp.flags.CustomFlag; import io.lumine.mythic.lib.comp.flags.CustomFlag;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -54,14 +53,14 @@ public class PvPModeListener implements Listener {
if (targetData.getLevel() < minLevel) { if (targetData.getLevel() < minLevel) {
event.setCancelled(true); event.setCancelled(true);
if (event.getDamage() > 0) 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; return;
} }
if (sourceData.getLevel() < minLevel) { if (sourceData.getLevel() < minLevel) {
event.setCancelled(true); event.setCancelled(true);
if (event.getDamage() > 0) 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; return;
} }
@ -69,7 +68,7 @@ public class PvPModeListener implements Listener {
if (maxLevelDiff > 0 && Math.abs(targetData. getLevel() - sourceData.getLevel()) > maxLevelDiff) { if (maxLevelDiff > 0 && Math.abs(targetData. getLevel() - sourceData.getLevel()) > maxLevelDiff) {
event.setCancelled(true); event.setCancelled(true);
if (event.getDamage() > 0) 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; return;
} }
} }
@ -81,7 +80,7 @@ public class PvPModeListener implements Listener {
if (targetData.getCombat().isInvulnerable()) { if (targetData.getCombat().isInvulnerable()) {
if (event.getDamage() > 0) { if (event.getDamage() > 0) {
final long left = targetData.getCombat().getInvulnerableTill() - System.currentTimeMillis(); 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); "left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source);
} }
event.setCancelled(true); event.setCancelled(true);
@ -92,7 +91,7 @@ public class PvPModeListener implements Listener {
if (!MMOCore.plugin.configManager.pvpModeInvulnerabilityCanDamage && sourceData.getCombat().isInvulnerable()) { if (!MMOCore.plugin.configManager.pvpModeInvulnerabilityCanDamage && sourceData.getCombat().isInvulnerable()) {
if (event.getDamage() > 0) { if (event.getDamage() > 0) {
final long left = sourceData.getCombat().getInvulnerableTill() - System.currentTimeMillis(); 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); "left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source);
} }
event.setCancelled(true); event.setCancelled(true);
@ -109,14 +108,14 @@ public class PvPModeListener implements Listener {
if (!targetData.getCombat().isInPvpMode()) { if (!targetData.getCombat().isInPvpMode()) {
event.setCancelled(true); event.setCancelled(true);
if (event.getDamage() > 0) 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 // Attacker has not enabled PvP mode
else if (!sourceData.getCombat().isInPvpMode()) { else if (!sourceData.getCombat().isInPvpMode()) {
event.setCancelled(true); event.setCancelled(true);
if (event.getDamage() > 0) 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 * @param file Text file to read data from
* @throws IOException IO exception when reading file * @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(" ", "-"); this.id = file.getName().replace(".txt", "").toLowerCase().replace("_", "-").replace(" ", "-");
try {
BufferedReader reader = new BufferedReader(new FileReader(file)); BufferedReader reader = new BufferedReader(new FileReader(file));
String readLine; String readLine;
while ((readLine = reader.readLine()) != null) while ((readLine = reader.readLine()) != null)
@ -46,9 +45,6 @@ public class ExpCurve {
reader.close(); reader.close();
Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve"); 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; package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -11,8 +10,7 @@ import javax.annotation.Nullable;
* General implementation for professions, classes and attributes. * General implementation for professions, classes and attributes.
* <p> * <p>
* An experience object is a type of object that can level up. * An experience object is a type of object that can level up.
* It has an experience curve and table and can receive EXP. It * It has an experience curve and table and can receive EXP
* is what most resembles the Mythic abstraction of "archetypes".
* *
* @author jules * @author jules
*/ */
@ -38,17 +36,4 @@ public interface ExperienceObject extends ExperienceDispenser {
ExperienceTable getExperienceTable(); ExperienceTable getExperienceTable();
boolean hasExperienceTable(); 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; 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.MythicLib;
import io.lumine.mythic.lib.UtilityMethods; 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.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
@ -18,6 +18,7 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -85,7 +86,7 @@ public class PlayerProfessions {
* When loading data through SQL * When loading data through SQL
*/ */
public void load(String json) { 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 // Load profession exp and levels
for (Entry<String, JsonElement> entry : obj.entrySet()) for (Entry<String, JsonElement> entry : obj.entrySet())
@ -99,6 +100,14 @@ public class PlayerProfessions {
if (obj.has("timesClaimed")) if (obj.has("timesClaimed"))
for (Entry<String, JsonElement> entry : obj.getAsJsonObject("timesClaimed").entrySet()) for (Entry<String, JsonElement> entry : obj.getAsJsonObject("timesClaimed").entrySet())
playerData.getItemClaims().put("profession." + entry.getKey(), entry.getValue().getAsInt()); playerData.getItemClaims().put("profession." + entry.getKey(), entry.getValue().getAsInt());
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
if (profession.hasExperienceTable())
profession.getExperienceTable().claimRemovableTrigger(playerData, profession);
}
if (playerData.getProfess().hasExperienceTable())
playerData.getProfess().getExperienceTable().claimRemovableTrigger(playerData, playerData.getProfess());
} }
public PlayerData getPlayerData() { public PlayerData getPlayerData() {
@ -154,11 +163,11 @@ public class PlayerProfessions {
return profession.hasMaxLevel() && getLevel(profession) >= profession.getMaxLevel(); 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); 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"); Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player");
if (value <= 0) { if (value <= 0) {
exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0d) + value)); exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0d) + value));
@ -189,8 +198,8 @@ public class PlayerProfessions {
return; return;
// Display hologram // Display hologram
if (hologramLocation != null && profession.getOption(Profession.ProfessionOption.EXP_HOLOGRAMS)) if (hologramLocation != null)
MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), ConfigMessage.fromKey("exp-hologram", "exp", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience())).asLine()); 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())); exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0d) + event.getExperience()));
int level, oldLevel = getLevel(profession); int level, oldLevel = getLevel(profession);
@ -214,24 +223,25 @@ public class PlayerProfessions {
playerData.giveExperience(profession.getExperience().calculate(level), null); playerData.giveExperience(profession.getExperience().calculate(level), null);
// Apply profession experience table // Apply profession experience table
profession.updateAdvancement(playerData, level); if (profession.hasExperienceTable())
profession.getExperienceTable().claim(playerData, level, profession);
} }
if (check) { if (check) {
Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level)); Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level));
new SmallParticleEffect(playerData.getPlayer(), VParticle.INSTANT_EFFECT.get()); new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT);
ConfigMessage.fromKey("profession-level-up").addPlaceholders("level", String.valueOf(level), "profession", profession.getName()) new ConfigMessage("profession-level-up").addPlaceholders("level", String.valueOf(level), "profession", profession.getName())
.send(playerData.getPlayer()); .send(playerData.getPlayer());
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(playerData.getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_UP).playTo(playerData.getPlayer());
playerData.getStats().updateStats(); playerData.getStats().updateStats();
} }
StringBuilder bar = new StringBuilder(ChatColor.BOLD.toString()); StringBuilder bar = new StringBuilder("" + ChatColor.BOLD);
int chars = (int) (exp / needed * 20); int chars = (int) (exp / needed * 20);
for (int j = 0; j < 20; j++) 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()) 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()); MythicLib.plugin.getMMOConfig().decimal.format(exp / needed * 100)).send(playerData.getPlayer());
} }
} }

View File

@ -1,8 +1,7 @@
package net.Indyuce.mmocore.experience; package net.Indyuce.mmocore.experience;
import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.util.PostLoadAction; import io.lumine.mythic.lib.api.util.PostLoadObject;
import io.lumine.mythic.lib.util.PreloadedObject;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
@ -19,7 +18,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Level; 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 String id, name;
private final int maxLevel; private final int maxLevel;
private final Map<ProfessionOption, Boolean> options = new HashMap<>(); private final Map<ProfessionOption, Boolean> options = new HashMap<>();
@ -32,14 +31,8 @@ public class Profession implements ExperienceObject, PreloadedObject {
*/ */
private final LinearValue experience; private final LinearValue experience;
private final PostLoadAction postLoadAction = new PostLoadAction(config -> { public Profession(String id, FileConfiguration config) {
super(config);
// Link profession to hardcoded profession manager
MMOCore.plugin.professionManager.loadProfessionConfigurations(this, config);
});
public Profession(String id, ConfigurationSection config) {
postLoadAction.cacheConfig(config);
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-"); this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
this.name = config.getString("name"); this.name = config.getString("name");
@ -81,10 +74,9 @@ public class Profession implements ExperienceObject, PreloadedObject {
} }
} }
@NotNull
@Override @Override
public PostLoadAction getPostLoadAction() { protected void whenPostLoaded(ConfigurationSection configurationSection) {
return postLoadAction; MMOCore.plugin.professionManager.loadProfessionConfigurations(this, configurationSection);
} }
public boolean getOption(ProfessionOption option) { public boolean getOption(ProfessionOption option) {
@ -101,7 +93,7 @@ public class Profession implements ExperienceObject, PreloadedObject {
@Override @Override
public String getKey() { public String getKey() {
return "profession_" + getId(); return "profession." + getId();
} }
@Override @Override
@ -132,7 +124,8 @@ public class Profession implements ExperienceObject, PreloadedObject {
} }
@Override @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); 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; 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 * experience given in a specific profession. Also being used to
* monitor EXP holograms. * monitor EXP holograms.
* *

View File

@ -3,9 +3,9 @@ package net.Indyuce.mmocore.experience.droptable;
import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.Trigger;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable; 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.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
@ -132,11 +132,12 @@ public class ExperienceItem {
} }
/** /**
* Used when a player logs back, in order to apply again * Used when a player connects back to give back all the stats that he should have.
* all the temporary triggers. *
* @param playerData
*/ */
public void applyTemporaryTriggers(PlayerData playerData) { public void applyRemovableTrigger(PlayerData playerData) {
for (Trigger trigger : triggers) 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 net.Indyuce.mmocore.experience.ExperienceObject;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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 levelingUp Player leveling up
* @param professionLevel New profession level * @param professionLevel New profession level
* @param object The object being level up. This MUST be the parent object * @param object Either profession or class leveling up
* owning the calling experience table! In other words,
* <code>object.getExperienceTable() == this</code> must remain true.
*/ */
public void claim(@NotNull PlayerData levelingUp, int professionLevel, @NotNull ExperienceObject object) { public void claim(PlayerData levelingUp, int professionLevel, ExperienceObject object) {
for (ExperienceItem item : items) { for (ExperienceItem item : items) {
final int timesClaimed = levelingUp.getClaims(object, item); int timesClaimed = levelingUp.getClaims(object, this, item);
if (!item.roll(professionLevel, timesClaimed)) continue; if (!item.roll(professionLevel, timesClaimed))
continue;
levelingUp.setClaims(object, item, timesClaimed + 1); levelingUp.setClaims(object, this, item, timesClaimed + 1);
item.applyTriggers(levelingUp); 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) { for (ExperienceItem item : items) {
int timesClaimed = playerData.getClaims(object, this, item);
// Undo triggers for (int i = 0; i < timesClaimed; i++)
for (int i = 0; i < playerData.getClaims(object, item); i++)
item.removeTriggers(playerData); item.removeTriggers(playerData);
// Reset levels
if (reset) playerData.setClaims(object, item, 0);
} }
} }
/** /**
* Called when a player joins. All non-permanent/temporary triggers * Called when the progression is reset(e.g skill tree reallocation)
* must be granted back to the player, including player modifiers. */
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 data PlayerData
* @param object Either profession, skillTreeNode or class leveling up * @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) { 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++) 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 io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.EXPSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
@ -44,12 +44,9 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
@Override @Override
public ExperienceSourceManager<BrewPotionExperienceSource> newManager() { public ExperienceSourceManager<BrewPotionExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<BrewPotionExperienceSource>() {
}
private static class Manager extends ExperienceSourceManager<BrewPotionExperienceSource> { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BrewEvent event) { public void a(BrewEvent event) {
Optional<Player> playerOpt = getNearbyPlayer(event.getBlock().getLocation()); Optional<Player> playerOpt = getNearbyPlayer(event.getBlock().getLocation());
if (!playerOpt.isPresent()) if (!playerOpt.isPresent())
@ -65,9 +62,11 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
PlayerData data = PlayerData.get(playerOpt.get()); PlayerData data = PlayerData.get(playerOpt.get());
for (BrewPotionExperienceSource source : getSources()) for (BrewPotionExperienceSource source : getSources())
if (source.matches(data, (PotionMeta) brewn.getItemMeta())) 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) { private ItemStack findPotion(BrewerInventory inv) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
@ -81,9 +80,8 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
private Optional<Player> getNearbyPlayer(Location loc) { private Optional<Player> getNearbyPlayer(Location loc) {
return loc.getWorld().getPlayers().stream().filter(player -> player.getLocation().distanceSquared(loc) < 100).findAny(); 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 * if the potion was extended using redstone or upgraded using
@ -163,14 +161,14 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
// effect.getType() == type).findFirst(); // effect.getType() == type).findFirst();
// } // }
public void process(BrewPotionExperienceSource source, Player player) { public void process(Player player) {
/* /*
* calculate extra exp due to extra effects * calculate extra exp due to extra effects
*/ */
// exp += getTotal(mapEffectDurations()); // 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 org.bukkit.event.player.PlayerMoveEvent;
import static org.bukkit.event.EventPriority.HIGHEST; import static org.bukkit.event.EventPriority.HIGHEST;
import static org.bukkit.event.EventPriority.MONITOR;
public class ClimbExperienceSource extends SpecificExperienceSource<Material> { public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
//Can be Ladder,Vines,Twisting Vines,Weeping Vines. //Can be Ladder,Vines,Twisting Vines,Weeping Vines.
@ -35,28 +36,14 @@ public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
type = Material.valueOf(str); type = Material.valueOf(str);
} }
} }
@Override @Override
public ExperienceSourceManager<ClimbExperienceSource> newManager() { public ExperienceSourceManager<ClimbExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<ClimbExperienceSource>() {
}
@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> {
@EventHandler(priority = HIGHEST,ignoreCancelled = true) @EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onClimb(PlayerMoveEvent e) { public void onClimb(PlayerMoveEvent e) {
double delta=e.getTo().getBlockY()-e.getFrom().getBlockY(); 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 io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -30,19 +30,11 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
@Override @Override
public ExperienceSourceManager<CraftItemExperienceSource> newManager() { public ExperienceSourceManager<CraftItemExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<CraftItemExperienceSource>() {
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<CraftItemExperienceSource> {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void a(CraftItemEvent event) { 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()); PlayerData data = PlayerData.get((Player) event.getWhoClicked());
@ -72,7 +64,8 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
// First check // First check
int newAmount = getAmount(event.getInventory().getMatrix()[index]); int newAmount = getAmount(event.getInventory().getMatrix()[index]);
if (newAmount >= oldAmount) return; if (newAmount >= oldAmount)
return;
// Deduce amount crafted // Deduce amount crafted
int amountCrafted = (event.getClick().isShiftClick() ? oldAmount - newAmount : 1) * itemsCraftedPerRecipe; 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()); source.giveExperience(data, amountCrafted, event.getInventory().getLocation());
}); });
} }
};
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private int getAmount(@Nullable ItemStack item) { private int getAmount(@Nullable ItemStack item) {
return item == null || item.getType() == Material.AIR ? 0 : item.getAmount(); return item == null || item.getType() == Material.AIR ? 0 : item.getAmount();
@ -102,4 +102,3 @@ public class CraftItemExperienceSource extends SpecificExperienceSource<Material
return index; return index;
} }
} }
}

View File

@ -1,16 +1,16 @@
package net.Indyuce.mmocore.experience.source; 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.MMOLineConfig;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent; import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.damage.DamagePacket;
import io.lumine.mythic.lib.damage.DamageType; import io.lumine.mythic.lib.damage.DamageType;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource; import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.attribute.Attribute;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
@ -18,7 +18,7 @@ import java.util.stream.Collectors;
import static org.bukkit.event.EventPriority.MONITOR; import static org.bukkit.event.EventPriority.MONITOR;
public class DamageDealtExperienceSource extends SpecificExperienceSource<Void> { public class DamageDealtExperienceSource extends SpecificExperienceSource<DamageType> {
private final DamageType type; private final DamageType type;
/** /**
@ -28,40 +28,51 @@ public class DamageDealtExperienceSource extends SpecificExperienceSource<Void>
public DamageDealtExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) { public DamageDealtExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config); super(dispenser, config);
if (!config.contains("type")) type = null; if (!config.contains("type"))
type = null;
else { else {
String str = UtilityMethods.enumName(config.getString("type")); String str = config.getString("type").toUpperCase().replace("-", "_");
//Checks if the damage type correspond to a value of the damage type enum //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); type = DamageType.valueOf(str);
} }
} }
@Override @Override
public ExperienceSourceManager<DamageDealtExperienceSource> newManager() { 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 @Override
public boolean matchesParameter(PlayerData player, Void v) { public boolean matchesParameter(PlayerData player, DamageType damageType) {
if (type == null) {
return true; 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; 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.MMOLineConfig;
import io.lumine.mythic.lib.util.Lazy;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource; import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.attribute.Attribute; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
@ -43,40 +41,34 @@ public class DamageTakenExperienceSource extends SpecificExperienceSource<Entity
@Override @Override
public ExperienceSourceManager<DamageTakenExperienceSource> newManager() { public ExperienceSourceManager<DamageTakenExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<DamageTakenExperienceSource>() {
}
@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> {
@EventHandler(priority = HIGHEST,ignoreCancelled = true) @EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onDamageTaken(EntityDamageEvent event) { public void onDamageTaken(EntityDamageEvent e) {
if (!UtilityMethods.isRealPlayer(event.getEntity())) return; if (e.getEntity() instanceof Player && !e.getEntity().hasMetadata("NPC")) {
double amount = e.getDamage();
final PlayerData playerData = PlayerData.get((Player) event.getEntity()); PlayerData playerData = PlayerData.get((OfflinePlayer) e.getEntity());
final Lazy<Double> effectiveDamage = Lazy.of(() -> { //We wait 2 tick to check if the player is Dead
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
new BukkitRunnable() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
for (DamageTakenExperienceSource source : getSources()) for (DamageTakenExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, event.getCause())) { if (source.matchesParameter(playerData, e.getCause()))
// System.out.println("-> " + effectiveDamage.get()); source.giveExperience(playerData, amount, null);
source.giveExperience(playerData, effectiveDamage.get(), null);
} }
} }
}.runTaskLater(MMOCore.plugin, 2); }.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 @Override
public ExperienceSourceManager<EatExperienceSource> newManager() { public ExperienceSourceManager<EatExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<EatExperienceSource>() {
}
@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> {
@EventHandler(priority = MONITOR,ignoreCancelled = true) @EventHandler(priority = MONITOR,ignoreCancelled = true)
public void a(PlayerItemConsumeEvent e) { 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 io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; 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.EXPSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -41,12 +41,9 @@ public class EnchantItemExperienceSource extends ExperienceSource<Void> {
@Override @Override
public ExperienceSourceManager<EnchantItemExperienceSource> newManager() { public ExperienceSourceManager<EnchantItemExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<EnchantItemExperienceSource>() {
}
private static class Manager extends ExperienceSourceManager<EnchantItemExperienceSource> { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(EnchantItemEvent event) { public void a(EnchantItemEvent event) {
PlayerData player = PlayerData.get(event.getEnchanter()); PlayerData player = PlayerData.get(event.getEnchanter());
for (EnchantItemExperienceSource source : getSources()) for (EnchantItemExperienceSource source : getSources())
@ -63,8 +60,9 @@ public class EnchantItemExperienceSource extends ExperienceSource<Void> {
double exp = 0; double exp = 0;
for (Entry<Enchantment, Integer> entry : applicableEnchants.entrySet()) for (Entry<Enchantment, Integer> entry : applicableEnchants.entrySet())
exp += MMOCore.plugin.enchantManager.getBaseExperience(entry.getKey()) * entry.getValue(); 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 io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; 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.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Item; import org.bukkit.entity.Item;
@ -25,17 +25,9 @@ public class FishItemExperienceSource extends SpecificExperienceSource<ItemStack
@Override @Override
public ExperienceSourceManager<FishItemExperienceSource> newManager() { public ExperienceSourceManager<FishItemExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<FishItemExperienceSource>() {
}
@Override @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public boolean matchesParameter(PlayerData player, ItemStack obj) {
return obj.getType() == material;
}
private static class Manager extends ExperienceSourceManager<FishItemExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(PlayerFishEvent event) { public void a(PlayerFishEvent event) {
if (event.getState() == State.CAUGHT_FISH) { if (event.getState() == State.CAUGHT_FISH) {
ItemStack caught = ((Item) event.getCaught()).getItemStack(); 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)); 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 @Override
public ExperienceSourceManager<FromExperienceSource> newManager() { public ExperienceSourceManager<FromExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<>() {
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return false;
}
private static class Manager extends ExperienceSourceManager<FromExperienceSource> {
/** /**
* Used to register all the children experience sources. * Used to register all the children experience sources.
@ -50,5 +42,11 @@ public class FromExperienceSource extends ExperienceSource {
public void registerSource(FromExperienceSource source) { public void registerSource(FromExperienceSource source) {
source.experienceSources.forEach(expSource -> MMOCore.plugin.experience.registerSource(expSource)); source.experienceSources.forEach(expSource -> MMOCore.plugin.experience.registerSource(expSource));
} }
};
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return false;
} }
} }

View File

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

View File

@ -1,11 +1,10 @@
package net.Indyuce.mmocore.experience.source; package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.MythicLib; 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.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; 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.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@ -22,7 +21,7 @@ public class MineBlockExperienceSource extends SpecificExperienceSource<Material
/** /**
* Set to false by default. * Set to false by default.
* <p> *
* When set to true, the exp source will trigger when breaking * When set to true, the exp source will trigger when breaking
* blocks that were placed by players. This can be used for crops * blocks that were placed by players. This can be used for crops
*/ */
@ -40,36 +39,37 @@ public class MineBlockExperienceSource extends SpecificExperienceSource<Material
@Override @Override
public ExperienceSourceManager<MineBlockExperienceSource> newManager() { public ExperienceSourceManager<MineBlockExperienceSource> newManager() {
return new Manager(); return
} new ExperienceSourceManager<MineBlockExperienceSource>() {
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<MineBlockExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BlockBreakEvent event) { public void a(BlockBreakEvent event) {
if (event.getPlayer().getGameMode() != GameMode.SURVIVAL) return; if (event.getPlayer().getGameMode() != GameMode.SURVIVAL)
if (UtilityMethods.isFake(event)) return; return;
PlayerData data = PlayerData.get(event.getPlayer()); PlayerData data = PlayerData.get(event.getPlayer());
for (MineBlockExperienceSource source : getSources()) { 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())) if (source.crop && !MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock()))
continue; 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())) if (source.matches(data, event.getBlock().getType()))
source.giveExperience(data, 1, event.getBlock().getLocation()); source.giveExperience(data, 1, event.getBlock().getLocation());
} }
} }
};
}
private boolean hasSilkTouch(ItemStack item) { private boolean hasSilkTouch(ItemStack item) {
return item != null && item.hasItemMeta() && item.getItemMeta().hasEnchant(Enchantment.SILK_TOUCH); 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 @Override
public ExperienceSourceManager<MoveExperienceSource> newManager() { 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 @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 io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; 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.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material; import org.bukkit.Material;
@ -23,16 +23,7 @@ public class PlaceBlockExperienceSource extends SpecificExperienceSource<Materia
@Override @Override
public ExperienceSourceManager<PlaceBlockExperienceSource> newManager() { public ExperienceSourceManager<PlaceBlockExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<PlaceBlockExperienceSource>() {
}
@Override
public boolean matchesParameter(PlayerData player, Material obj) {
return material == obj;
}
private static class Manager extends ExperienceSourceManager<PlaceBlockExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BlockPlaceEvent event) { public void a(BlockPlaceEvent event) {
@ -44,5 +35,11 @@ public class PlaceBlockExperienceSource extends SpecificExperienceSource<Materia
if (source.matches(data, event.getBlock().getType())) if (source.matches(data, event.getBlock().getType()))
source.giveExperience(data, 1, event.getBlock().getLocation()); 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; 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.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
@ -15,13 +14,14 @@ import org.bukkit.scheduler.BukkitRunnable;
import java.util.Objects; import java.util.Objects;
public class PlayExperienceSource extends SpecificExperienceSource { public class PlayExperienceSource extends SpecificExperienceSource {
private final World world; private final World world;
private final double x1, x2, z1, z2; private final double x1, x2, z1, z2;
private final boolean inCombat; private final boolean inCombat;
/** /**
* Experience source giving the specified amount of xp to all the players online each second in certain world bounds. * 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. * has to be inCombat or not to get the xp.
*/ */
public PlayExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) { public PlayExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
@ -47,7 +47,7 @@ public class PlayExperienceSource extends SpecificExperienceSource {
@Override @Override
public ExperienceSourceManager<PlayExperienceSource> newManager() { 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() { new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
Bukkit.getOnlinePlayers().forEach(player -> { Bukkit.getOnlinePlayers().forEach((player) -> {
if (UtilityMethods.isRealPlayer(player)) { if (!player.hasMetadata("NPC")) {
PlayerData playerData = PlayerData.get(player); PlayerData playerData = PlayerData.get(player);
for (PlayExperienceSource source : getSources()) for (PlayExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, null)) 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; 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.MMOLineConfig;
import io.lumine.mythic.lib.util.FlushableRegistry; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource; 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.EntityDamageByEntityEvent;
import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -29,7 +30,8 @@ public class ProjectileExperienceSource extends SpecificExperienceSource<Project
public ProjectileExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) { public ProjectileExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config); super(dispenser, config);
if (!config.contains("type")) projectileType = null; if (!config.contains("type"))
projectileType = null;
else { else {
String str = config.getString("type").toUpperCase().replace("-", "_"); String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(Arrays.stream(ProjectileType.values()).map(ProjectileType::toString).collect(Collectors.toList()).contains(str)); 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 @Override
public ExperienceSourceManager<ProjectileExperienceSource> newManager() { 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 @Override
public boolean matchesParameter(PlayerData player, Projectile projectile) { public boolean matchesParameter(PlayerData player, Projectile projectile) {
if (projectileType == null) return true; if (projectileType == null)
return true;
return projectileType.matches(projectile); return projectileType.matches(projectile);
} }
public enum ProjectileType { 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; 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

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.experience.source; 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.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
@ -41,20 +40,20 @@ public class RepairItemExperienceSource extends ExperienceSource<ItemStack> {
@Override @Override
public ExperienceSourceManager<RepairItemExperienceSource> newManager() { 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) { 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; return;
// Check if there's exp associated to it // Check if there's exp associated to it
final @Nullable ItemStack item = event.getCurrentItem(); final ItemStack item = event.getCurrentItem();
if (UtilityMethods.isAir(item)) return; if (!MMOCore.plugin.smithingManager.hasExperience(item.getType()))
if (!MMOCore.plugin.smithingManager.hasExperience(item.getType())) return; return;
final PlayerData data = PlayerData.get((Player) event.getWhoClicked()); final PlayerData data = PlayerData.get((Player) event.getWhoClicked());
for (RepairItemExperienceSource source : getSources()) for (RepairItemExperienceSource source : getSources())
@ -80,7 +79,7 @@ public class RepairItemExperienceSource extends ExperienceSource<ItemStack> {
*/ */
final double exp = MMOCore.plugin.smithingManager.getBaseExperience(item.getType()) final double exp = MMOCore.plugin.smithingManager.getBaseExperience(item.getType())
* Math.max(0, ((Damageable) old.getItemMeta()).getDamage() - ((Damageable) item.getItemMeta()).getDamage()) / 100; * 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; 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.MMOLineConfig;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource; import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -22,37 +21,39 @@ public class ResourceExperienceSource extends SpecificExperienceSource<PlayerRes
*/ */
public ResourceExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) { public ResourceExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config); super(dispenser, config);
if (!config.contains("type")) resource = null; if (!config.contains("type"))
resource = null;
else { else {
String str = config.getString("type").toUpperCase().replace("-", "_"); 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); resource = PlayerResource.valueOf(str);
} }
} }
@Override @Override
public ExperienceSourceManager<ResourceExperienceSource> newManager() { 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 @Override
public boolean matchesParameter(PlayerData player, PlayerResource obj) { 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); 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; 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.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
@ -41,7 +40,29 @@ public class RideExperienceSource extends SpecificExperienceSource<EntityType> {
@Override @Override
public ExperienceSourceManager<RideExperienceSource> newManager() { 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 @Override
@ -51,25 +72,4 @@ public class RideExperienceSource extends SpecificExperienceSource<EntityType> {
return type.equals(obj); 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);
}
}
}
}
} }

View File

@ -2,8 +2,8 @@ package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; 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.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -27,31 +27,29 @@ public class SmeltItemExperienceSource extends SpecificExperienceSource<ItemStac
@Override @Override
public ExperienceSourceManager<SmeltItemExperienceSource> newManager() { public ExperienceSourceManager<SmeltItemExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<SmeltItemExperienceSource>() {
}
@Override @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public boolean matchesParameter(PlayerData player, ItemStack obj) {
return obj.getType() == material;
}
private static class Manager extends ExperienceSourceManager<SmeltItemExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void a(BlockCookEvent event) { public void a(BlockCookEvent event) {
Optional<Player> player = getNearestPlayer(event.getBlock().getLocation()); Optional<Player> player = getNearestPlayer(event.getBlock().getLocation());
if (!player.isPresent()) return; if (!player.isPresent())
return;
ItemStack caught = event.getResult(); ItemStack caught = event.getResult();
if (caught.hasItemMeta()) return; if (caught.hasItemMeta())
return;
PlayerData data = PlayerData.get(player.get()); PlayerData data = PlayerData.get(player.get());
for (SmeltItemExperienceSource source : getSources()) for (SmeltItemExperienceSource source : getSources())
if (source.matches(data, caught)) source.giveExperience(data, 1, event.getBlock().getLocation()); if (source.matches(data, caught))
source.giveExperience(data, 1, event.getBlock().getLocation());
}
};
} }
private Optional<Player> getNearestPlayer(Location loc) { private Optional<Player> getNearestPlayer(Location loc) {
final Player[] nearby = loc.getWorld().getPlayers().stream().filter(player -> player.getLocation().distanceSquared(loc) < 100).toArray(Player[]::new); final Player[] nearby = loc.getWorld().getPlayers().stream().filter(player -> player.getLocation().distanceSquared(loc) < 100)
.toArray(Player[]::new);
Player selected = null; Player selected = null;
double lastDist = 100; double lastDist = 100;
for (Player p : nearby) { for (Player p : nearby) {
@ -63,5 +61,9 @@ public class SmeltItemExperienceSource extends SpecificExperienceSource<ItemStac
} }
return Optional.ofNullable(selected); return Optional.ofNullable(selected);
} }
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
return obj.getType() == material;
} }
} }

View File

@ -1,6 +1,5 @@
package net.Indyuce.mmocore.experience.source; 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.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
@ -8,44 +7,39 @@ import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource; import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf; import org.bukkit.entity.Wolf;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityTameEvent;
public class TameExperienceSource extends SpecificExperienceSource<EntityType> { import static org.bukkit.event.EventPriority.HIGHEST;
public class TameExperienceSource extends SpecificExperienceSource {
public TameExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) { public TameExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config); super(dispenser, config);
} }
@Override @Override
public ExperienceSourceManager<TameExperienceSource> newManager() { public ExperienceSourceManager<TameExperienceSource> newManager() {
return new Manager(); return new ExperienceSourceManager<TameExperienceSource>() {
@EventHandler(priority = HIGHEST,ignoreCancelled = true)
public void onWolfHit(EntityDamageByEntityEvent e) {
if(e.getDamager() instanceof Wolf) {
Wolf wolf= (Wolf) e.getDamager();
if(wolf.getOwner() instanceof Player &&!((Player) wolf.getOwner()).hasMetadata("NPC")) {
PlayerData playerData=PlayerData.get((OfflinePlayer) wolf.getOwner());
for(TameExperienceSource source:getSources()) {
source.giveExperience(playerData,e.getDamage(), MMOCoreUtils.getCenterLocation(e.getEntity()));
}
}
}
}
};
} }
@Override @Override
public boolean matchesParameter(PlayerData player, EntityType entityType) { public boolean matchesParameter(PlayerData player, Object obj) {
return true; return false;
}
private static class Manager extends ExperienceSourceManager<TameExperienceSource> {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onWolfHit(EntityTameEvent event) {
// Only wolves at the moment
if (!(event.getEntity() instanceof Wolf)) return;
if (!(event.getOwner() instanceof Player) || !UtilityMethods.isRealPlayer((Entity) event.getOwner()))
return;
PlayerData playerData = PlayerData.get((OfflinePlayer) event.getOwner());
for (TameExperienceSource source : getSources())
if (source.matches(playerData, event.getEntity().getType()))
source.giveExperience(playerData, 1, MMOCoreUtils.getCenterLocation(event.getEntity()));
}
} }
} }

View File

@ -2,7 +2,6 @@ package net.Indyuce.mmocore.gui;
import io.lumine.mythic.lib.manager.StatManager; import io.lumine.mythic.lib.manager.StatManager;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.GeneratedInventory;
@ -96,13 +95,13 @@ public class AttributeView extends EditableInventory {
if (item.getFunction().equalsIgnoreCase("reallocation")) { if (item.getFunction().equalsIgnoreCase("reallocation")) {
int spent = playerData.getAttributes().countPoints(); int spent = playerData.getAttributes().countPoints();
if (spent < 1) { if (spent < 1) {
ConfigMessage.fromKey("no-attribute-points-spent").send(player); MMOCore.plugin.configManager.getSimpleMessage("no-attribute-points-spent").send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
return; return;
} }
if (playerData.getAttributeReallocationPoints() < 1) { if (playerData.getAttributeReallocationPoints() < 1) {
ConfigMessage.fromKey("not-attribute-reallocation-point").send(player); MMOCore.plugin.configManager.getSimpleMessage("not-attribute-reallocation-point").send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
return; return;
} }
@ -110,7 +109,7 @@ public class AttributeView extends EditableInventory {
playerData.getAttributes().getInstances().forEach(ins -> ins.setBase(0)); playerData.getAttributes().getInstances().forEach(ins -> ins.setBase(0));
playerData.giveAttributePoints(spent); playerData.giveAttributePoints(spent);
playerData.giveAttributeReallocationPoints(-1); playerData.giveAttributeReallocationPoints(-1);
ConfigMessage.fromKey("attribute-points-reallocated", "points", String.valueOf(playerData.getAttributePoints())).send(player); MMOCore.plugin.configManager.getSimpleMessage("attribute-points-reallocated", "points", "" + playerData.getAttributePoints()).send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.RESET_ATTRIBUTES).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.RESET_ATTRIBUTES).playTo(getPlayer());
open(); open();
} }
@ -119,14 +118,14 @@ public class AttributeView extends EditableInventory {
PlayerAttribute attribute = ((AttributeItem) item).attribute; PlayerAttribute attribute = ((AttributeItem) item).attribute;
if (playerData.getAttributePoints() < 1) { if (playerData.getAttributePoints() < 1) {
ConfigMessage.fromKey("not-attribute-point").send(player); MMOCore.plugin.configManager.getSimpleMessage("not-attribute-point").send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
return; return;
} }
PlayerAttributes.AttributeInstance ins = playerData.getAttributes().getInstance(attribute); PlayerAttributes.AttributeInstance ins = playerData.getAttributes().getInstance(attribute);
if (attribute.hasMax() && ins.getBase() >= attribute.getMax()) { if (attribute.hasMax() && ins.getBase() >= attribute.getMax()) {
ConfigMessage.fromKey("attribute-max-points-hit").send(player); MMOCore.plugin.configManager.getSimpleMessage("attribute-max-points-hit").send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
return; return;
} }
@ -138,7 +137,7 @@ public class AttributeView extends EditableInventory {
pointsSpent = Math.min(pointsSpent, attribute.getMax() - ins.getBase()); pointsSpent = Math.min(pointsSpent, attribute.getMax() - ins.getBase());
if (shiftClick && playerData.getAttributePoints() < pointsSpent) { if (shiftClick && playerData.getAttributePoints() < pointsSpent) {
ConfigMessage.fromKey("not-attribute-point-shift", "shift_points", String.valueOf(pointsSpent)).send(player); MMOCore.plugin.configManager.getSimpleMessage("not-attribute-point-shift", "shift_points", String.valueOf(pointsSpent)).send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.NOT_ENOUGH_POINTS).playTo(getPlayer());
return; return;
} }
@ -147,10 +146,11 @@ public class AttributeView extends EditableInventory {
playerData.giveAttributePoints(-pointsSpent); playerData.giveAttributePoints(-pointsSpent);
// Apply exp table as many times as required // Apply exp table as many times as required
if (attribute.hasExperienceTable())
while (pointsSpent-- > 0) while (pointsSpent-- > 0)
attribute.updateAdvancement(playerData, ins.getBase()); attribute.getExperienceTable().claim(playerData, ins.getBase(), attribute);
ConfigMessage.fromKey("attribute-level-up", "attribute", attribute.getName(), "level", String.valueOf(ins.getBase())).send(player); MMOCore.plugin.configManager.getSimpleMessage("attribute-level-up", "attribute", attribute.getName(), "level", String.valueOf(ins.getBase())).send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_ATTRIBUTE).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.LEVEL_ATTRIBUTE).playTo(getPlayer());
PlayerAttributeUseEvent playerAttributeUseEvent = new PlayerAttributeUseEvent(playerData, attribute); PlayerAttributeUseEvent playerAttributeUseEvent = new PlayerAttributeUseEvent(playerData, attribute);

View File

@ -2,7 +2,6 @@ package net.Indyuce.mmocore.gui;
import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent; import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
@ -145,8 +144,8 @@ public class ClassConfirmation extends EditableInventory {
playerData.setClass(profess); playerData.setClass(profess);
else else
(playerData.hasSavedClass(profess) ? playerData.getClassInfo(profess) (playerData.hasSavedClass(profess) ? playerData.getClassInfo(profess)
: new SavedClassInformation(MMOCore.plugin.playerDataManager.getDefaultData())).load(profess, playerData); : new SavedClassInformation(MMOCore.plugin.dataProvider.getDataManager().getDefaultData())).load(profess, playerData);
ConfigMessage.fromKey("class-select", "class", profess.getName()).send(player); MMOCore.plugin.configManager.getSimpleMessage("class-select", "class", profess.getName()).send(player);
MMOCore.plugin.soundManager.getSound(SoundEvent.SELECT_CLASS).playTo(player); MMOCore.plugin.soundManager.getSound(SoundEvent.SELECT_CLASS).playTo(player);
player.closeInventory(); player.closeInventory();
if (profileRunnable != null) profileRunnable.run(); if (profileRunnable != null) profileRunnable.run();

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