mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-06-28 11:44:42 +02:00
Merge upstream into fixed kotlin script changes.
Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
This commit is contained in:
@ -11,6 +11,7 @@ dependencies {
|
||||
exclude(Deps.Groups.guava, Deps.Modules.guava)
|
||||
exclude(Deps.Groups.checker, Deps.Modules.checker)
|
||||
}
|
||||
compile(Libs.flowmath)
|
||||
compile(Libs.jdbc)
|
||||
compile(Libs.juli)
|
||||
testCompile(Libs.junitDep)
|
||||
|
@ -1,5 +0,0 @@
|
||||
package com.gmail.nossr50;
|
||||
|
||||
public class McmmoCore {
|
||||
|
||||
}
|
73
core/src/main/java/com/gmail/nossr50/core/McmmoCore.java
Normal file
73
core/src/main/java/com/gmail/nossr50/core/McmmoCore.java
Normal file
@ -0,0 +1,73 @@
|
||||
package com.gmail.nossr50.core;
|
||||
|
||||
import com.gmail.nossr50.core.data.database.DatabaseManager;
|
||||
import com.gmail.nossr50.core.mcmmo.event.EventCommander;
|
||||
import com.gmail.nossr50.core.mcmmo.plugin.Plugin;
|
||||
import com.gmail.nossr50.core.mcmmo.server.Server;
|
||||
import com.gmail.nossr50.core.mcmmo.tasks.TaskScheduler;
|
||||
import com.gmail.nossr50.core.platform.Platform;
|
||||
import com.gmail.nossr50.core.util.ModManager;
|
||||
import com.gmail.nossr50.core.util.experience.FormulaManager;
|
||||
import com.gmail.nossr50.core.util.upgrade.UpgradeManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class McmmoCore {
|
||||
//TODO: Wire all this stuff
|
||||
public static Plugin p;
|
||||
private static EventCommander eventCommander;
|
||||
private static Logger logger;
|
||||
private static Platform platform;
|
||||
private static boolean retroModeEnabled;
|
||||
|
||||
//Why do all these things need to be here? Sigh...
|
||||
private static DatabaseManager databaseManager;
|
||||
private static UpgradeManager upgradeManager; //TODO: I can't even remember what this one did
|
||||
private static FormulaManager formulaManager;
|
||||
private static ModManager modManager; //TODO: Probably need to rewrite this
|
||||
|
||||
/**
|
||||
* Returns our Logger
|
||||
* @return the logger
|
||||
*/
|
||||
public static Logger getLogger()
|
||||
{
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static EventCommander getEventCommander() {
|
||||
return eventCommander;
|
||||
}
|
||||
|
||||
public static Server getServer() {
|
||||
return platform.getServer();
|
||||
}
|
||||
|
||||
public static TaskScheduler getTaskScheduler()
|
||||
{
|
||||
return platform.getScheduler();
|
||||
}
|
||||
|
||||
public static java.io.InputStream getResource(String path)
|
||||
{
|
||||
return platform.getResource(path);
|
||||
}
|
||||
|
||||
public static File getDataFolderPath()
|
||||
{
|
||||
return platform.getDataFolderPath();
|
||||
}
|
||||
|
||||
public static DatabaseManager getDatabaseManager() { return databaseManager; }
|
||||
|
||||
public static UpgradeManager getUpgradeManager() { return upgradeManager; }
|
||||
|
||||
public static FormulaManager getFormulaManager() { return formulaManager; }
|
||||
|
||||
public static boolean isRetroModeEnabled() { return retroModeEnabled; }
|
||||
|
||||
public static ModManager getModManager() { return modManager; }
|
||||
|
||||
public static String getModDataFolderPath() { return platform.getModDataFolderPath(); }
|
||||
}
|
34
core/src/main/java/com/gmail/nossr50/core/TODO
Normal file
34
core/src/main/java/com/gmail/nossr50/core/TODO
Normal file
@ -0,0 +1,34 @@
|
||||
This file is just going to take note of all the caveats of mcMMO code as I abstract out bukkit
|
||||
|
||||
1) In several places mcMMO is disabling itself, pretty sure this is not a good idea and this should be changed
|
||||
eg: in McMMOPlayer, and when loading configs and finding bad values
|
||||
|
||||
2) mcMMO uses a a global reference of its Plugin class for Bukkit in order to schedule tasks
|
||||
|
||||
3) Need to configure the logger
|
||||
|
||||
4) Safety check the hardcore/vampirism commands
|
||||
|
||||
5) Tweak configs to not do any string operations
|
||||
|
||||
6) Need to add and check validation for all current configs
|
||||
|
||||
7) Weird stuff going on with ageables and strings in general in StringUtils
|
||||
|
||||
8) Reduce the amount of string operations in mcMMO as much as possible
|
||||
|
||||
|
||||
|
||||
////////////
|
||||
|
||||
CONFIG NOTES
|
||||
|
||||
///////////
|
||||
|
||||
1) All Config files need their validation redone and checked
|
||||
|
||||
2) All Config files need unload programmed in
|
||||
|
||||
3) All Config files need string operations reduced and to be double checked for errors in paths
|
||||
|
||||
4) Need to setup removing old keys on configs
|
@ -0,0 +1,89 @@
|
||||
package com.gmail.nossr50.core.api;
|
||||
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.player.McMMOPlayer;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Living;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.runnables.skills.BleedTimerTask;
|
||||
import com.gmail.nossr50.core.skills.SuperAbilityType;
|
||||
|
||||
public final class AbilityAPI {
|
||||
private AbilityAPI() {
|
||||
}
|
||||
|
||||
public static boolean berserkEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.BERSERK);
|
||||
}
|
||||
|
||||
public static boolean gigaDrillBreakerEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER);
|
||||
}
|
||||
|
||||
public static boolean greenTerraEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.GREEN_TERRA);
|
||||
}
|
||||
|
||||
public static boolean serratedStrikesEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
|
||||
}
|
||||
|
||||
public static boolean skullSplitterEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SKULL_SPLITTER);
|
||||
}
|
||||
|
||||
public static boolean superBreakerEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.SUPER_BREAKER);
|
||||
}
|
||||
|
||||
public static boolean treeFellerEnabled(Player player) {
|
||||
return UserManager.getPlayer(player).getAbilityMode(SuperAbilityType.TREE_FELLER);
|
||||
}
|
||||
|
||||
public static boolean isAnyAbilityEnabled(Player player) {
|
||||
McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
|
||||
|
||||
for (SuperAbilityType ability : SuperAbilityType.values()) {
|
||||
if (mcMMOPlayer.getAbilityMode(ability)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void resetCooldowns(Player player) {
|
||||
UserManager.getPlayer(player).resetCooldowns();
|
||||
}
|
||||
|
||||
public static void setBerserkCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.BERSERK, cooldown);
|
||||
}
|
||||
|
||||
public static void setGigaDrillBreakerCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER, cooldown);
|
||||
}
|
||||
|
||||
public static void setGreenTerraCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.GREEN_TERRA, cooldown);
|
||||
}
|
||||
|
||||
public static void setSerratedStrikesCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SERRATED_STRIKES, cooldown);
|
||||
}
|
||||
|
||||
public static void setSkullSplitterCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SKULL_SPLITTER, cooldown);
|
||||
}
|
||||
|
||||
public static void setSuperBreakerCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.SUPER_BREAKER, cooldown);
|
||||
}
|
||||
|
||||
public static void setTreeFellerCooldown(Player player, long cooldown) {
|
||||
UserManager.getPlayer(player).setAbilityDATS(SuperAbilityType.TREE_FELLER, cooldown);
|
||||
}
|
||||
|
||||
public static boolean isBleeding(Living entity) {
|
||||
return BleedTimerTask.isBleeding(entity);
|
||||
}
|
||||
}
|
153
core/src/main/java/com/gmail/nossr50/core/api/ChatAPI.java
Normal file
153
core/src/main/java/com/gmail/nossr50/core/api/ChatAPI.java
Normal file
@ -0,0 +1,153 @@
|
||||
package com.gmail.nossr50.core.api;
|
||||
|
||||
import com.gmail.nossr50.core.chat.ChatManager;
|
||||
import com.gmail.nossr50.core.chat.ChatManagerFactory;
|
||||
import com.gmail.nossr50.core.chat.PartyChatManager;
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.chat.ChatMode;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.party.PartyManager;
|
||||
|
||||
public final class ChatAPI {
|
||||
private ChatAPI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all members of a party
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param plugin The plugin sending the message
|
||||
* @param sender The name of the sender
|
||||
* @param displayName The display name of the sender
|
||||
* @param party The name of the party to send to
|
||||
* @param message The message to send
|
||||
*/
|
||||
public static void sendPartyChat(Plugin plugin, String sender, String displayName, String party, String message) {
|
||||
getPartyChatManager(plugin, party).handleChat(sender, displayName, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all members of a party
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param plugin The plugin sending the message
|
||||
* @param sender The name of the sender to display in the chat
|
||||
* @param party The name of the party to send to
|
||||
* @param message The message to send
|
||||
*/
|
||||
public static void sendPartyChat(Plugin plugin, String sender, String party, String message) {
|
||||
getPartyChatManager(plugin, party).handleChat(sender, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to administrators
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param plugin The plugin sending the message
|
||||
* @param sender The name of the sender
|
||||
* @param displayName The display name of the sender
|
||||
* @param message The message to send
|
||||
*/
|
||||
public static void sendAdminChat(Plugin plugin, String sender, String displayName, String message) {
|
||||
ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN).handleChat(sender, displayName, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to administrators
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param plugin The plugin sending the message
|
||||
* @param sender The name of the sender to display in the chat
|
||||
* @param message The message to send
|
||||
*/
|
||||
public static void sendAdminChat(Plugin plugin, String sender, String message) {
|
||||
ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN).handleChat(sender, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player is currently talking in party chat.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return true if the player is using party chat, false otherwise
|
||||
*/
|
||||
public static boolean isUsingPartyChat(Player player) {
|
||||
return UserManager.getPlayer(player).isChatEnabled(ChatMode.PARTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player is currently talking in party chat.
|
||||
*
|
||||
* @param playerName The name of the player to check
|
||||
* @return true if the player is using party chat, false otherwise
|
||||
*/
|
||||
public static boolean isUsingPartyChat(String playerName) {
|
||||
return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.PARTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player is currently talking in admin chat.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return true if the player is using admin chat, false otherwise
|
||||
*/
|
||||
public static boolean isUsingAdminChat(Player player) {
|
||||
return UserManager.getPlayer(player).isChatEnabled(ChatMode.ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player is currently talking in admin chat.
|
||||
*
|
||||
* @param playerName The name of the player to check
|
||||
* @return true if the player is using admin chat, false otherwise
|
||||
*/
|
||||
public static boolean isUsingAdminChat(String playerName) {
|
||||
return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the party chat mode of a player.
|
||||
*
|
||||
* @param player The player to toggle party chat on.
|
||||
*/
|
||||
public static void togglePartyChat(Player player) {
|
||||
UserManager.getPlayer(player).toggleChat(ChatMode.PARTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the party chat mode of a player.
|
||||
*
|
||||
* @param playerName The name of the player to toggle party chat on.
|
||||
*/
|
||||
public static void togglePartyChat(String playerName) {
|
||||
UserManager.getPlayer(playerName).toggleChat(ChatMode.PARTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the admin chat mode of a player.
|
||||
*
|
||||
* @param player The player to toggle admin chat on.
|
||||
*/
|
||||
public static void toggleAdminChat(Player player) {
|
||||
UserManager.getPlayer(player).toggleChat(ChatMode.ADMIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the admin chat mode of a player.
|
||||
*
|
||||
* @param playerName The name of the player to toggle party chat on.
|
||||
*/
|
||||
public static void toggleAdminChat(String playerName) {
|
||||
UserManager.getPlayer(playerName).toggleChat(ChatMode.ADMIN);
|
||||
}
|
||||
|
||||
private static ChatManager getPartyChatManager(Plugin plugin, String party) {
|
||||
ChatManager chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.PARTY);
|
||||
((PartyChatManager) chatManager).setParty(PartyManager.getParty(party));
|
||||
|
||||
return chatManager;
|
||||
}
|
||||
}
|
1103
core/src/main/java/com/gmail/nossr50/core/api/ExperienceAPI.java
Normal file
1103
core/src/main/java/com/gmail/nossr50/core/api/ExperienceAPI.java
Normal file
File diff suppressed because it is too large
Load Diff
241
core/src/main/java/com/gmail/nossr50/core/api/PartyAPI.java
Normal file
241
core/src/main/java/com/gmail/nossr50/core/api/PartyAPI.java
Normal file
@ -0,0 +1,241 @@
|
||||
package com.gmail.nossr50.core.api;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.interactions.NotificationType;
|
||||
import com.gmail.nossr50.core.datatypes.party.Party;
|
||||
import com.gmail.nossr50.core.datatypes.party.PartyLeader;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.party.PartyManager;
|
||||
import com.gmail.nossr50.core.util.player.NotificationManager;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class PartyAPI {
|
||||
private PartyAPI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the party a player is in.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check the party name of
|
||||
* @return the name of the player's party, or null if not in a party
|
||||
*/
|
||||
public static String getPartyName(Player player) {
|
||||
if (!inParty(player)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return UserManager.getPlayer(player).getParty().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a player is in a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return true if the player is in a party, false otherwise
|
||||
*/
|
||||
public static boolean inParty(Player player) {
|
||||
return UserManager.getPlayer(player).inParty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two players are in the same party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param playera The first player to check
|
||||
* @param playerb The second player to check
|
||||
* @return true if the two players are in the same party, false otherwise
|
||||
*/
|
||||
public static boolean inSameParty(Player playera, Player playerb) {
|
||||
return PartyManager.inSameParty(playera, playerb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all current parties.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return the list of parties.
|
||||
*/
|
||||
public static List<Party> getParties() {
|
||||
return PartyManager.getParties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a player to a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to add to the party
|
||||
* @param partyName The party to add the player to
|
||||
* @deprecated parties can have limits, use the other method
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addToParty(Player player, String partyName) {
|
||||
Party party = PartyManager.getParty(partyName);
|
||||
|
||||
if (party == null) {
|
||||
party = new Party(new PartyLeader(player.getUUID(), player.getName()), partyName);
|
||||
} else {
|
||||
if (PartyManager.isPartyFull(player, party)) {
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull", party.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PartyManager.addToParty(UserManager.getPlayer(player), party);
|
||||
}
|
||||
|
||||
/**
|
||||
* The max party size of the server
|
||||
* 0 or less for no size limit
|
||||
*
|
||||
* @return the max party size on this server
|
||||
*/
|
||||
public static int getMaxPartySize() {
|
||||
return MainConfig.getInstance().getPartyMaxSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a player to a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to add to the party
|
||||
* @param partyName The party to add the player to
|
||||
* @param bypassLimit if true bypasses party size limits
|
||||
*/
|
||||
public static void addToParty(Player player, String partyName, boolean bypassLimit) {
|
||||
Party party = PartyManager.getParty(partyName);
|
||||
|
||||
if (party == null) {
|
||||
party = new Party(new PartyLeader(player.getUUID(), player.getName()), partyName);
|
||||
}
|
||||
|
||||
PartyManager.addToParty(UserManager.getPlayer(player), party);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a player from a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to remove
|
||||
*/
|
||||
public static void removeFromParty(Player player) {
|
||||
PartyManager.removeFromParty(UserManager.getPlayer(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the leader of a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param partyName The party name
|
||||
* @return the leader of the party
|
||||
*/
|
||||
public static String getPartyLeader(String partyName) {
|
||||
return PartyManager.getPartyLeaderName(partyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the leader of a party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param partyName The name of the party to set the leader of
|
||||
* @param playerName The playerName to set as leader
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setPartyLeader(String partyName, String playerName) {
|
||||
PartyManager.setPartyLeader(McmmoCore.getServer().getOfflinePlayer(playerName).getUniqueId(), PartyManager.getParty(partyName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all players in this player's party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return all the players in the player's party
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<OfflinePlayer> getOnlineAndOfflineMembers(Player player) {
|
||||
List<OfflinePlayer> members = new ArrayList<OfflinePlayer>();
|
||||
|
||||
for (UUID memberUniqueId : PartyManager.getAllMembers(player).keySet()) {
|
||||
OfflinePlayer member = mcMMO.p.getServer().getOfflinePlayer(memberUniqueId);
|
||||
members.add(member);
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all player names in this player's party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return all the player names in the player's party
|
||||
*/
|
||||
@Deprecated
|
||||
public static LinkedHashSet<String> getMembers(Player player) {
|
||||
return (LinkedHashSet<String>) PartyManager.getAllMembers(player).values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all player names and uuids in this player's party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return all the player names and uuids in the player's party
|
||||
*/
|
||||
public static LinkedHashMap<UUID, String> getMembersMap(Player player) {
|
||||
return PartyManager.getAllMembers(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all online players in this party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param partyName The party to check
|
||||
* @return all online players in this party
|
||||
*/
|
||||
public static List<Player> getOnlineMembers(String partyName) {
|
||||
return PartyManager.getOnlineMembers(partyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all online players in this player's party.
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @param player The player to check
|
||||
* @return all online players in the player's party
|
||||
*/
|
||||
public static List<Player> getOnlineMembers(Player player) {
|
||||
return PartyManager.getOnlineMembers(player);
|
||||
}
|
||||
|
||||
public static boolean hasAlly(String partyName) {
|
||||
return getAllyName(partyName) != null;
|
||||
}
|
||||
|
||||
public static String getAllyName(String partyName) {
|
||||
Party ally = PartyManager.getParty(partyName).getAlly();
|
||||
if (ally != null) {
|
||||
return ally.getName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
94
core/src/main/java/com/gmail/nossr50/core/api/SkillAPI.java
Normal file
94
core/src/main/java/com/gmail/nossr50/core/api/SkillAPI.java
Normal file
@ -0,0 +1,94 @@
|
||||
package com.gmail.nossr50.core.api;
|
||||
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class SkillAPI {
|
||||
private SkillAPI() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This includes parent and child skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getSkills() {
|
||||
return getListFromEnum(Arrays.asList(PrimarySkillType.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This only includes parent skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getNonChildSkills() {
|
||||
return getListFromEnum(PrimarySkillType.NON_CHILD_SKILLS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This only includes child skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getChildSkills() {
|
||||
return getListFromEnum(PrimarySkillType.CHILD_SKILLS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This only includes combat skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getCombatSkills() {
|
||||
return getListFromEnum(PrimarySkillType.COMBAT_SKILLS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This only includes gathering skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getGatheringSkills() {
|
||||
return getListFromEnum(PrimarySkillType.GATHERING_SKILLS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of strings with mcMMO's skills
|
||||
* This only includes misc skills
|
||||
* </br>
|
||||
* This function is designed for API usage.
|
||||
*
|
||||
* @return a list of strings with valid skill names
|
||||
*/
|
||||
public static List<String> getMiscSkills() {
|
||||
return getListFromEnum(PrimarySkillType.MISC_SKILLS);
|
||||
}
|
||||
|
||||
private static List<String> getListFromEnum(List<PrimarySkillType> skillsTypes) {
|
||||
List<String> skills = new ArrayList<String>();
|
||||
|
||||
for (PrimarySkillType primarySkillType : skillsTypes) {
|
||||
skills.add(primarySkillType.name());
|
||||
}
|
||||
|
||||
return skills;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.api.exceptions;
|
||||
|
||||
public class InvalidFormulaTypeException extends RuntimeException {
|
||||
private static final long serialVersionUID = 3368670229490121886L;
|
||||
|
||||
public InvalidFormulaTypeException() {
|
||||
super("That is not a valid FormulaType.");
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.api.exceptions;
|
||||
|
||||
public class InvalidPlayerException extends RuntimeException {
|
||||
private static final long serialVersionUID = 907213002618581385L;
|
||||
|
||||
public InvalidPlayerException() {
|
||||
super("That player does not exist in the database.");
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.api.exceptions;
|
||||
|
||||
public class InvalidSkillException extends RuntimeException {
|
||||
private static final long serialVersionUID = 942705284195791157L;
|
||||
|
||||
public InvalidSkillException() {
|
||||
super("That is not a valid skill.");
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.api.exceptions;
|
||||
|
||||
public class InvalidXPGainReasonException extends RuntimeException {
|
||||
private static final long serialVersionUID = 4427052841957931157L;
|
||||
|
||||
public InvalidXPGainReasonException() {
|
||||
super("That is not a valid XPGainReason.");
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.gmail.nossr50.core.api.exceptions;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
|
||||
public class McMMOPlayerNotFoundException extends RuntimeException {
|
||||
private static final long serialVersionUID = 761917904993202836L;
|
||||
|
||||
public McMMOPlayerNotFoundException(Player player) {
|
||||
super("McMMOPlayer object was not found for: " + player.getName() + " " + player.getUUID());
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.gmail.nossr50.core.chat;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.events.chat.McMMOAdminChatEvent;
|
||||
|
||||
public class AdminChatManager extends ChatManager {
|
||||
protected AdminChatManager() {
|
||||
super(MainConfig.getInstance().getAdminDisplayNames(), MainConfig.getInstance().getAdminChatPrefix());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleChat(String senderName, String displayName, String message, boolean isAsync) {
|
||||
handleChat(new McMMOAdminChatEvent(senderName, displayName, message, isAsync));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage() {
|
||||
McmmoCore.getServer().broadcast(message, "mcmmo.chat.adminchat");
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.gmail.nossr50.core.chat;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.party.Party;
|
||||
import com.gmail.nossr50.core.events.chat.McMMOChatEvent;
|
||||
import com.gmail.nossr50.core.events.chat.McMMOPartyChatEvent;
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
|
||||
public abstract class ChatManager {
|
||||
protected boolean useDisplayNames;
|
||||
protected String chatPrefix;
|
||||
|
||||
protected String senderName;
|
||||
protected String displayName;
|
||||
protected String message;
|
||||
|
||||
protected ChatManager(boolean useDisplayNames, String chatPrefix) {
|
||||
this.useDisplayNames = useDisplayNames;
|
||||
this.chatPrefix = chatPrefix;
|
||||
}
|
||||
|
||||
protected void handleChat(McMMOChatEvent event) {
|
||||
McmmoCore.getEventCommander().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
senderName = event.getSender();
|
||||
displayName = useDisplayNames ? event.getDisplayName() : senderName;
|
||||
message = LocaleLoader.formatString(chatPrefix, displayName) + " " + event.getMessage();
|
||||
|
||||
sendMessage();
|
||||
|
||||
/*
|
||||
* Party Chat Spying
|
||||
* Party messages will be copied to people with the mcmmo.admin.chatspy permission node
|
||||
*/
|
||||
if (event instanceof McMMOPartyChatEvent) {
|
||||
//We need to grab the party chat name
|
||||
McMMOPartyChatEvent partyChatEvent = (McMMOPartyChatEvent) event;
|
||||
|
||||
//Find the people with permissions
|
||||
for (Player player : McmmoCore.getServer().getOnlinePlayers()) {
|
||||
//Check for toggled players
|
||||
if (UserManager.getPlayer(player).isPartyChatSpying()) {
|
||||
Party adminParty = UserManager.getPlayer(player).getParty();
|
||||
|
||||
//Only message admins not part of this party
|
||||
if (adminParty != null) {
|
||||
//TODO: Incorporate JSON
|
||||
if (!adminParty.getName().equalsIgnoreCase(partyChatEvent.getParty()))
|
||||
player.sendMessage(LocaleLoader.getString("Commands.AdminChatSpy.Chat", partyChatEvent.getParty(), message));
|
||||
} else {
|
||||
player.sendMessage(LocaleLoader.getString("Commands.AdminChatSpy.Chat", partyChatEvent.getParty(), message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleChat(String senderName, String message) {
|
||||
handleChat(senderName, senderName, message, false);
|
||||
}
|
||||
|
||||
public void handleChat(Player player, String message, boolean isAsync) {
|
||||
handleChat(player.getName(), player.getDisplayName(), message, isAsync);
|
||||
}
|
||||
|
||||
public void handleChat(String senderName, String displayName, String message) {
|
||||
handleChat(senderName, displayName, message, false);
|
||||
}
|
||||
|
||||
public abstract void handleChat(String senderName, String displayName, String message, boolean isAsync);
|
||||
|
||||
protected abstract void sendMessage();
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.gmail.nossr50.core.chat;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.chat.ChatMode;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ChatManagerFactory {
|
||||
private static final HashMap<Plugin, AdminChatManager> adminChatManagers = new HashMap<Plugin, AdminChatManager>();
|
||||
private static final HashMap<Plugin, PartyChatManager> partyChatManagers = new HashMap<Plugin, PartyChatManager>();
|
||||
|
||||
public static ChatManager getChatManager(Plugin plugin, ChatMode mode) {
|
||||
switch (mode) {
|
||||
case ADMIN:
|
||||
if (!adminChatManagers.containsKey(plugin)) {
|
||||
adminChatManagers.put(plugin, new AdminChatManager(plugin));
|
||||
}
|
||||
|
||||
return adminChatManagers.get(plugin);
|
||||
case PARTY:
|
||||
if (!partyChatManagers.containsKey(plugin)) {
|
||||
partyChatManagers.put(plugin, new PartyChatManager(plugin));
|
||||
}
|
||||
|
||||
return partyChatManagers.get(plugin);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.gmail.nossr50.core.chat;
|
||||
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.datatypes.party.Party;
|
||||
import com.gmail.nossr50.core.events.chat.McMMOPartyChatEvent;
|
||||
import com.gmail.nossr50.core.runnables.party.PartyChatTask;
|
||||
|
||||
public class PartyChatManager extends ChatManager {
|
||||
private Party party;
|
||||
|
||||
protected PartyChatManager(Plugin plugin) {
|
||||
super(plugin, MainConfig.getInstance().getPartyDisplayNames(), MainConfig.getInstance().getPartyChatPrefix());
|
||||
}
|
||||
|
||||
public void setParty(Party party) {
|
||||
this.party = party;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleChat(String senderName, String displayName, String message, boolean isAsync) {
|
||||
handleChat(new McMMOPartyChatEvent(plugin, senderName, displayName, party.getName(), message, isAsync));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage() {
|
||||
new PartyChatTask(plugin, party, senderName, displayName, message).runTask(plugin);
|
||||
}
|
||||
}
|
@ -0,0 +1,723 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.datatypes.interactions.NotificationType;
|
||||
import com.gmail.nossr50.core.mcmmo.colors.ChatColor;
|
||||
import com.gmail.nossr50.core.skills.SubSkillType;
|
||||
import com.gmail.nossr50.core.skills.subskills.AbstractSubSkill;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
//@ConfigSerializable
|
||||
public class AdvancedConfig extends ConfigValidated {
|
||||
|
||||
public static final String SKILLS = "Skills";
|
||||
public static final String GENERAL = "General";
|
||||
public static final String ABILITY = "Ability";
|
||||
public static final String LENGTH = "Length";
|
||||
public static final String INCREASE_LEVEL = "IncreaseLevel";
|
||||
public static final String ENCHANT_BUFF = "EnchantBuff";
|
||||
public static final String ACROBATICS = "Acrobatics";
|
||||
public static final String DODGE = "Dodge";
|
||||
public static final String CHANCE = "Chance";
|
||||
public static final String CHANCE_MAX = CHANCE + "Max";
|
||||
public static final String BONUS = "Bonus";
|
||||
public static final String MAX_BONUS_LEVEL = "Max" + BONUS + "Level";
|
||||
public static final String MODIFIER = "Modifier";
|
||||
public static final String DAMAGE_MODIFIER = "Damage" + MODIFIER;
|
||||
public static final String DAMAGE_THRESHOLD = "DamageThreshold";
|
||||
public static final String ALCHEMY = "Alchemy";
|
||||
public static final String CATALYSIS = "Catalysis";
|
||||
public static final String MIN_SPEED = "MinSpeed";
|
||||
public static final String MAX_SPEED = "MaxSpeed";
|
||||
public static final String ARCHERY = "Archery";
|
||||
public static final String SKILL_SHOT = "SkillShot";
|
||||
public static final String MULTIPLIER = "Multiplier";
|
||||
public static final String RANK_DAMAGE_MULTIPLIER = "RankDamage" + MULTIPLIER;
|
||||
public static final String BONUS_DAMAGE = BONUS + "Damage";
|
||||
public static final String FORCE_MULTIPLIER = "Force" + MULTIPLIER;
|
||||
public static final String AXES = "Axes";
|
||||
public static final String STANDARD = "Standard";
|
||||
public static final String RETRO_MODE = "RetroMode";
|
||||
public static final String CAP_LEVEL = "CapLevel";
|
||||
public static final String KNOCKBACK_MODIFIER = "Knockback" + MODIFIER;
|
||||
public static final String PVP_MODIFIER = "PVP_" + MODIFIER;
|
||||
public static final String PVE_MODIFIER = "PVE_" + MODIFIER;
|
||||
public static final String FISHING = "Fishing";
|
||||
public static final String MASTER_ANGLER = "MasterAngler";
|
||||
public static final String BOAT_MODIFIER = "Boat" + MODIFIER;
|
||||
public static final String BIOME_MODIFIER = "Biome" + MODIFIER;
|
||||
public static final String XP = "XP";
|
||||
public static final String VANILLA_XPMULTIPLIER = "Vanilla" + XP + MULTIPLIER;
|
||||
public static final String RANK = "Rank_";
|
||||
public static final String TAMING = "Taming";
|
||||
public static final String CALL_OF_THE_WILD = "CallOfTheWild";
|
||||
public static final String MIN_HORSE_JUMP_STRENGTH = "MinHorseJumpStrength";
|
||||
public static final String MAX_HORSE_JUMP_STRENGTH = "MaxHorseJumpStrength";
|
||||
public static final String SHOCK_PROOF = "ShockProof";
|
||||
public static final String UNARMED = "Unarmed";
|
||||
public static final String STARTING_LEVEL = "StartingLevel";
|
||||
public static final String AXE_MASTERY = "AxeMastery";
|
||||
public static final String CRITICAL_STRIKES = "CriticalStrikes";
|
||||
public static final String GREATER_IMPACT = "GreaterImpact";
|
||||
public static final String ARMOR_IMPACT = "ArmorImpact";
|
||||
public static final String SKULL_SPLITTER = "SkullSplitter.";
|
||||
public static final String MAX_PERCENTAGE_DURABILITY_DAMAGE = "MaxPercentageDurabilityDamage";
|
||||
public static final String SHAKE = "Shake";
|
||||
public static final String MINING = "Mining";
|
||||
public static final String BLAST_MINING = "BlastMining";
|
||||
public static final String LEVELS = "Levels";
|
||||
public static final String BLAST_DAMAGE_DECREASE = "BlastDamageDecrease";
|
||||
public static final String ORE_BONUS = "Ore" + BONUS;
|
||||
public static final String DEBRIS_REDUCTION = "DebrisReduction";
|
||||
public static final String DROP_MULTIPLIER = "Drop" + MULTIPLIER;
|
||||
public static final String BLAST_RADIUS = "BlastRadius";
|
||||
public static final String REPAIR = "Repair";
|
||||
public static final String REPAIR_MASTERY = "RepairMastery";
|
||||
public static final String MAX_BONUS_PERCENTAGE = "Max" + BONUS + "Percentage";
|
||||
public static final String ARCANE_FORGING = "ArcaneForging";
|
||||
public static final String MAY_LOSE_ENCHANTS = "May_Lose_Enchants";
|
||||
public static final String KEEP_ENCHANTS = "Keep_Enchants_";
|
||||
public static final String DOWNGRADES = "Downgrades_";
|
||||
public static final String ENABLED = "Enabled";
|
||||
public static final String DOWNGRADES_ENABLED = DOWNGRADES + ENABLED;
|
||||
public static final String SALVAGE = "Salvage";
|
||||
public static final String ARCANE_SALVAGE = "ArcaneSalvage";
|
||||
public static final String ENCHANT_DOWNGRADE_ENABLED = "EnchantDowngrade" + ENABLED;
|
||||
public static final String ENCHANT_LOSS_ENABLED = "EnchantLoss" + ENABLED;
|
||||
public static final String EXTRACT_FULL_ENCHANT = "ExtractFullEnchant";
|
||||
public static final String EXTRACT_PARTIAL_ENCHANT = "ExtractPartialEnchant";
|
||||
public static final String SMELTING = "Smelting";
|
||||
public static final String FUEL_EFFICIENCY = "FuelEfficiency";
|
||||
public static final String FLUX = "Flux";
|
||||
public static final String SWORDS = "Swords";
|
||||
public static final String RUPTURE = "Rupture";
|
||||
public static final String DAMAGE_PLAYER = "DamagePlayer";
|
||||
public static final String DAMAGE_MOBS = "DamageMobs";
|
||||
public static final String MAX_TICKS = "MaxTicks";
|
||||
public static final String BASE_TICKS = "BaseTicks";
|
||||
public static final String COUNTER_ATTACK = "CounterAttack";
|
||||
public static final String SERRATED_STRIKES = "SerratedStrikes";
|
||||
public static final String TICKS = "Ticks";
|
||||
public static final String GORE = "Gore";
|
||||
public static final String FAST_FOOD = "FastFood";
|
||||
public static final String FAST_FOOD_SERVICE = FAST_FOOD + "Service";
|
||||
public static final String PUMMEL = "Pummel";
|
||||
public static final String THICK_FUR = "ThickFur";
|
||||
public static final String SHARPENED_CLAWS = "SharpenedClaws";
|
||||
public static final String DISARM = "Disarm";
|
||||
public static final String ANTI_THEFT = "AntiTheft";
|
||||
public static final String DAZE = "Daze";
|
||||
public static final String MAX_DAMAGE = "MaxDamage";
|
||||
public static final String ROLL = "Roll";
|
||||
public static final String GRACEFUL_ROLL = "Graceful" + ROLL;
|
||||
public static final String ARROW_DEFLECT = "ArrowDeflect";
|
||||
public static final String IRON_GRIP = "IronGrip";
|
||||
public static final String WOODCUTTING = "Woodcutting";
|
||||
public static final String HARVEST_LUMBER = "HarvestLumber";
|
||||
public static final String FEEDBACK = "Feedback";
|
||||
public static final String SKILL_COMMAND = "SkillCommand";
|
||||
public static final String BLANK_LINES_ABOVE_HEADER = "BlankLinesAboveHeader";
|
||||
public static final String ACTION_BAR_NOTIFICATIONS = "ActionBarNotifications";
|
||||
public static final String SEND_COPY_OF_MESSAGE_TO_CHAT = "SendCopyOfMessageToChat";
|
||||
public static final String EVENTS = "Events";
|
||||
public static final String SEND_TITLES = "SendTitles";
|
||||
private static AdvancedConfig instance;
|
||||
|
||||
private AdvancedConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), "advanced.yml", true);
|
||||
}
|
||||
|
||||
public static AdvancedConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AdvancedConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateKeys() {
|
||||
// Validate all the settings!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/* GENERAL */
|
||||
if (getAbilityLength() < 1) {
|
||||
reason.add(SKILLS + "." + GENERAL + "." + ABILITY + "." + LENGTH + ".<mode>." + INCREASE_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getEnchantBuff() < 1) {
|
||||
reason.add(SKILLS + "." + GENERAL + "." + ABILITY + "." + ENCHANT_BUFF + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* ACROBATICS */
|
||||
if (getMaximumProbability(SubSkillType.ACROBATICS_DODGE) < 1) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + DODGE + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.ACROBATICS_DODGE) < 1) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + DODGE + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getDodgeDamageModifier() <= 1) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + DODGE + "." + DAMAGE_MODIFIER + " should be greater than 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.ACROBATICS_ROLL) < 1) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + ROLL + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL) < 1) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + ROLL + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getRollDamageThreshold() < 0) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + ROLL + "." + DAMAGE_THRESHOLD + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getGracefulRollDamageThreshold() < 0) {
|
||||
reason.add(SKILLS + "." + ACROBATICS + "." + GRACEFUL_ROLL + "." + DAMAGE_THRESHOLD + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getCatalysisMinSpeed() <= 0) {
|
||||
reason.add(SKILLS + "." + ALCHEMY + "." + CATALYSIS + "." + MIN_SPEED + " must be greater than 0!");
|
||||
}
|
||||
|
||||
if (getCatalysisMaxSpeed() < getCatalysisMinSpeed()) {
|
||||
reason.add(SKILLS + "." + ALCHEMY + "." + CATALYSIS + "." + MAX_SPEED + " should be at least Skills.Alchemy.Catalysis." + MIN_SPEED + "!");
|
||||
}
|
||||
|
||||
/* ARCHERY */
|
||||
|
||||
if (getSkillShotRankDamageMultiplier() <= 0) {
|
||||
reason.add(SKILLS + "." + ARCHERY + "." + SKILL_SHOT + "." + RANK_DAMAGE_MULTIPLIER + " should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.ARCHERY_DAZE) < 1) {
|
||||
reason.add(SKILLS + "." + ARCHERY + "." + DAZE + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.ARCHERY_DAZE) < 1) {
|
||||
reason.add(SKILLS + "." + ARCHERY + "." + DAZE + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getDazeBonusDamage() < 0) {
|
||||
reason.add(SKILLS + "." + ARCHERY + "." + DAZE + "." + BONUS_DAMAGE + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.ARCHERY_ARROW_RETRIEVAL) < 1) {
|
||||
reason.add(SKILLS + "." + ARCHERY + ".Retrieve." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.ARCHERY_ARROW_RETRIEVAL) < 1) {
|
||||
reason.add(SKILLS + "." + ARCHERY + ".Retrieve." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getForceMultiplier() < 0) {
|
||||
reason.add(SKILLS + "." + ARCHERY + "." + FORCE_MULTIPLIER + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* AXES */
|
||||
if(getAxeMasteryRankDamageMultiplier() < 0)
|
||||
{
|
||||
reason.add(SKILLS + "." + AXES + "." + AXE_MASTERY + "." + RANK_DAMAGE_MULTIPLIER + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.AXES_CRITICAL_STRIKES) < 1) {
|
||||
reason.add(SKILLS + "." + AXES + ".CriticalHit." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.AXES_CRITICAL_STRIKES) < 1) {
|
||||
reason.add(SKILLS + "." + AXES + ".CriticalHit." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getCriticalStrikesPVPModifier() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + CRITICAL_STRIKES + "." + PVP_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getCriticalStrikesPVPModifier() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + CRITICAL_STRIKES + "." + PVE_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getGreaterImpactChance() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + GREATER_IMPACT + "." + CHANCE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getGreaterImpactModifier() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + GREATER_IMPACT + "." + KNOCKBACK_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getGreaterImpactBonusDamage() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + GREATER_IMPACT + "." + BONUS_DAMAGE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getArmorImpactIncreaseLevel() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + ARMOR_IMPACT + "." + INCREASE_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getImpactChance() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + ARMOR_IMPACT + "." + CHANCE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getArmorImpactMaxDurabilityDamage() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + ARMOR_IMPACT + "." + MAX_PERCENTAGE_DURABILITY_DAMAGE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getSkullSplitterModifier() < 1) {
|
||||
reason.add(SKILLS + "." + AXES + "." + SKULL_SPLITTER + DAMAGE_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
/*if (getFishermanDietRankChange() < 1) {
|
||||
reason.add(SKILLS + "." + FISHING + ".FishermansDiet.RankChange should be at least 1!");
|
||||
}*/
|
||||
|
||||
if (getMasterAnglerBoatModifier() < 1) {
|
||||
reason.add(SKILLS + "." + FISHING + "." + MASTER_ANGLER + "." + BOAT_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMasterAnglerBiomeModifier() < 1) {
|
||||
reason.add(SKILLS + "." + FISHING + "." + MASTER_ANGLER + "." + BIOME_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* HERBALISM */
|
||||
/*if (getFarmerDietRankChange() < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.FarmersDiet.RankChange should be at least 1!");
|
||||
}
|
||||
|
||||
if (getGreenThumbStageChange() < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.GreenThumb.StageChange should be at least 1!");
|
||||
}*/
|
||||
|
||||
if (getMaximumProbability(SubSkillType.HERBALISM_GREEN_THUMB) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.GreenThumb." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.HERBALISM_GREEN_THUMB) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.GreenThumb." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.HERBALISM_DOUBLE_DROPS) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.DoubleDrops." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.HERBALISM_DOUBLE_DROPS) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.DoubleDrops." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.HERBALISM_HYLIAN_LUCK) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.HylianLuck." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.HERBALISM_HYLIAN_LUCK) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.HylianLuck." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.HERBALISM_SHROOM_THUMB) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.ShroomThumb." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.HERBALISM_SHROOM_THUMB) < 1) {
|
||||
reason.add(SKILLS + ".Herbalism.ShroomThumb." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* MINING */
|
||||
if (getMaximumProbability(SubSkillType.MINING_DOUBLE_DROPS) < 1) {
|
||||
reason.add(SKILLS + "." + MINING + ".DoubleDrops." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.MINING_DOUBLE_DROPS) < 1) {
|
||||
reason.add(SKILLS + "." + MINING + ".DoubleDrops." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* REPAIR */
|
||||
if (getRepairMasteryMaxBonus() < 1) {
|
||||
reason.add(SKILLS + "." + REPAIR + "." + REPAIR_MASTERY + "." + MAX_BONUS_PERCENTAGE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getRepairMasteryMaxLevel() < 1) {
|
||||
reason.add(SKILLS + "." + REPAIR + "." + REPAIR_MASTERY + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.REPAIR_SUPER_REPAIR) < 1) {
|
||||
reason.add(SKILLS + "." + REPAIR + ".SuperRepair." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.REPAIR_SUPER_REPAIR) < 1) {
|
||||
reason.add(SKILLS + "." + REPAIR + ".SuperRepair." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* SMELTING */
|
||||
if (getBurnModifierMaxLevel() < 1) {
|
||||
reason.add(SKILLS + "." + SMELTING + "." + FUEL_EFFICIENCY + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getBurnTimeMultiplier() < 1) {
|
||||
reason.add(SKILLS + "." + SMELTING + "." + FUEL_EFFICIENCY + "." + MULTIPLIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.SMELTING_SECOND_SMELT) < 1) {
|
||||
reason.add(SKILLS + "." + SMELTING + ".SecondSmelt." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.SMELTING_SECOND_SMELT) < 1) {
|
||||
reason.add(SKILLS + "." + SMELTING + ".SecondSmelt." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getFluxMiningChance() < 1) {
|
||||
reason.add(SKILLS + "." + SMELTING + "." + FLUX + MINING + "." + CHANCE + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* SWORDS */
|
||||
if (getMaximumProbability(SubSkillType.SWORDS_RUPTURE) < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + RUPTURE + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.SWORDS_RUPTURE) < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + RUPTURE + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getRuptureMaxTicks() < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + RUPTURE + "." + MAX_TICKS + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getRuptureMaxTicks() < getRuptureBaseTicks()) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + RUPTURE + "." + MAX_TICKS + " should be at least Skills.Swords.Rupture." + BASE_TICKS + "!");
|
||||
}
|
||||
|
||||
if (getRuptureBaseTicks() < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + RUPTURE + "." + BASE_TICKS + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.SWORDS_COUNTER_ATTACK) < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + COUNTER_ATTACK + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.SWORDS_COUNTER_ATTACK) < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + COUNTER_ATTACK + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getCounterModifier() < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + COUNTER_ATTACK + "." + DAMAGE_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getSerratedStrikesModifier() < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + SERRATED_STRIKES + "." + DAMAGE_MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getSerratedStrikesTicks() < 1) {
|
||||
reason.add(SKILLS + "." + SWORDS + "." + SERRATED_STRIKES + "." + RUPTURE + "Ticks should be at least 1!");
|
||||
}
|
||||
|
||||
/* TAMING */
|
||||
|
||||
if (getMaximumProbability(SubSkillType.TAMING_GORE) < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + GORE + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.TAMING_GORE) < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + GORE + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getGoreModifier() < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + GORE + "." + MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getFastFoodChance() < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + FAST_FOOD + "." + CHANCE + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getThickFurModifier() < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + THICK_FUR + "." + MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getShockProofModifier() < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + SHOCK_PROOF + "." + MODIFIER + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getSharpenedClawsBonus() < 1) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + SHARPENED_CLAWS + "." + BONUS + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxHorseJumpStrength() < 0 || getMaxHorseJumpStrength() > 2) {
|
||||
reason.add(SKILLS + "." + TAMING + "." + CALL_OF_THE_WILD + "." + MAX_HORSE_JUMP_STRENGTH + " should be between 0 and 2!");
|
||||
}
|
||||
|
||||
/* UNARMED */
|
||||
if (getMaximumProbability(SubSkillType.UNARMED_DISARM) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + DISARM + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.UNARMED_DISARM) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + DISARM + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.UNARMED_ARROW_DEFLECT) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + ARROW_DEFLECT + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.UNARMED_ARROW_DEFLECT) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + ARROW_DEFLECT + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaximumProbability(SubSkillType.UNARMED_IRON_GRIP) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + IRON_GRIP + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.UNARMED_IRON_GRIP) < 1) {
|
||||
reason.add(SKILLS + "." + UNARMED + "." + IRON_GRIP + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
/* WOODCUTTING */
|
||||
|
||||
/*if (getLeafBlowUnlockLevel() < 0) {
|
||||
reason.add("Skills.Woodcutting.LeafBlower.UnlockLevel should be at least 0!");
|
||||
}*/
|
||||
|
||||
if (getMaximumProbability(SubSkillType.WOODCUTTING_HARVEST_LUMBER) < 1) {
|
||||
reason.add(SKILLS + "." + WOODCUTTING + "." + HARVEST_LUMBER + "." + CHANCE_MAX + " should be at least 1!");
|
||||
}
|
||||
|
||||
if (getMaxBonusLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER) < 1) {
|
||||
reason.add(SKILLS + "." + WOODCUTTING + "." + HARVEST_LUMBER + "." + MAX_BONUS_LEVEL + " should be at least 1!");
|
||||
}
|
||||
|
||||
return reason;
|
||||
}
|
||||
|
||||
/* GENERAL */
|
||||
public int getStartingLevel() { return getIntValue(SKILLS, GENERAL, STARTING_LEVEL); }
|
||||
|
||||
/**
|
||||
* This returns the maximum level at which superabilities will stop lengthening from scaling alongside skill level.
|
||||
* It returns a different value depending on whether or not the server is in retro mode
|
||||
* @return the level at which abilities stop increasing in length
|
||||
*/
|
||||
public int getAbilityLengthCap() {
|
||||
if(!McmmoCore.isRetroModeEnabled())
|
||||
return getIntValue(SKILLS, GENERAL, ABILITY, LENGTH, STANDARD, CAP_LEVEL);
|
||||
else
|
||||
return getIntValue(SKILLS, GENERAL, ABILITY, LENGTH, RETRO_MODE, CAP_LEVEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the frequency at which abilities will increase in length
|
||||
* It returns a different value depending on whether or not the server is in retro mode
|
||||
* @return the number of levels required per ability length increase
|
||||
*/
|
||||
public int getAbilityLength() {
|
||||
if(!McmmoCore.isRetroModeEnabled())
|
||||
return getIntValue(SKILLS, GENERAL, ABILITY, LENGTH, STANDARD, INCREASE_LEVEL);
|
||||
else
|
||||
return getIntValue(SKILLS, GENERAL, ABILITY, LENGTH, RETRO_MODE, INCREASE_LEVEL);
|
||||
}
|
||||
|
||||
public int getEnchantBuff() { return getIntValue(SKILLS, GENERAL, ABILITY, ENCHANT_BUFF); }
|
||||
|
||||
/**
|
||||
* Grabs the max bonus level for a skill used in RNG calculations
|
||||
* All max level values in the config are multiplied by 10 if the server is in retro mode as the values in the config are based around the new 1-100 skill system scaling
|
||||
* A value of 10 in the file will be returned as 100 for retro mode servers to accommodate the change in scaling
|
||||
* @param subSkillType target subskill
|
||||
* @return the level at which this skills max benefits will be reached on the curve
|
||||
*/
|
||||
public int getMaxBonusLevel(SubSkillType subSkillType) {
|
||||
String[] category = subSkillType.getAdvConfigAddress();
|
||||
|
||||
if(!McmmoCore.isRetroModeEnabled())
|
||||
return getIntValue(category[0], category[1], category[2], MAX_BONUS_LEVEL, STANDARD);
|
||||
else
|
||||
return getIntValue(category[0], category[1], category[2], MAX_BONUS_LEVEL, RETRO_MODE);
|
||||
}
|
||||
|
||||
public int getMaxBonusLevel(AbstractSubSkill abstractSubSkill) {
|
||||
return getMaxBonusLevel(abstractSubSkill.getSubSkillType());
|
||||
}
|
||||
|
||||
public double getMaximumProbability(SubSkillType subSkillType) {
|
||||
String[] category = subSkillType.getAdvConfigAddress();
|
||||
|
||||
double maximumProbability = getDoubleValue(category[0], category[1], category[2], CHANCE_MAX);
|
||||
|
||||
return maximumProbability;
|
||||
}
|
||||
|
||||
public double getMaximumProbability(AbstractSubSkill abstractSubSkill)
|
||||
{
|
||||
return getMaximumProbability(abstractSubSkill.getSubSkillType());
|
||||
}
|
||||
|
||||
/* Notification Settings */
|
||||
|
||||
public boolean doesSkillCommandSendBlankLines()
|
||||
{
|
||||
return getBooleanValue(FEEDBACK, SKILL_COMMAND, BLANK_LINES_ABOVE_HEADER);
|
||||
}
|
||||
|
||||
public boolean doesNotificationUseActionBar(NotificationType notificationType)
|
||||
{
|
||||
return getBooleanValue(FEEDBACK, ACTION_BAR_NOTIFICATIONS, notificationType.toString(), ENABLED);
|
||||
}
|
||||
|
||||
public boolean doesNotificationSendCopyToChat(NotificationType notificationType)
|
||||
{
|
||||
return getBooleanValue(FEEDBACK, ACTION_BAR_NOTIFICATIONS, notificationType.toString(), SEND_COPY_OF_MESSAGE_TO_CHAT);
|
||||
}
|
||||
|
||||
public boolean useTitlesForXPEvent()
|
||||
{
|
||||
return getBooleanValue(FEEDBACK, EVENTS, XP, SEND_TITLES);
|
||||
}
|
||||
|
||||
private ChatColor getChatColorFromKey(String keyLocation) {
|
||||
String colorName = getStringValue(keyLocation);
|
||||
|
||||
return getChatColor(colorName);
|
||||
}
|
||||
|
||||
private ChatColor getChatColor(String configColor) {
|
||||
for (ChatColor chatColor : ChatColor.values()) {
|
||||
if (configColor.equalsIgnoreCase(chatColor.toString()))
|
||||
return chatColor;
|
||||
}
|
||||
|
||||
//Invalid Color
|
||||
System.out.println("[mcMMO] " + configColor + " is an invalid color value");
|
||||
return ChatColor.WHITE;
|
||||
}
|
||||
|
||||
/* ACROBATICS */
|
||||
public double getDodgeDamageModifier() { return getDoubleValue(SKILLS, ACROBATICS, DODGE, DAMAGE_MODIFIER); }
|
||||
|
||||
public double getRollDamageThreshold() { return getDoubleValue(SKILLS, ACROBATICS, ROLL, DAMAGE_THRESHOLD); }
|
||||
|
||||
public double getGracefulRollDamageThreshold() { return getDoubleValue(SKILLS, ACROBATICS, GRACEFUL_ROLL, DAMAGE_THRESHOLD); }
|
||||
|
||||
/* ALCHEMY */
|
||||
public int getCatalysisMaxBonusLevel() { return getIntValue(SKILLS, ALCHEMY, CATALYSIS, MAX_BONUS_LEVEL); }
|
||||
|
||||
public double getCatalysisMinSpeed() { return getDoubleValue(SKILLS, ALCHEMY, CATALYSIS, MIN_SPEED); }
|
||||
public double getCatalysisMaxSpeed() { return getDoubleValue(SKILLS, ALCHEMY, CATALYSIS, MAX_SPEED); }
|
||||
|
||||
/* ARCHERY */
|
||||
public double getSkillShotRankDamageMultiplier() { return getDoubleValue(SKILLS, ARCHERY, SKILL_SHOT, RANK_DAMAGE_MULTIPLIER); }
|
||||
public double getSkillShotDamageMax() { return getDoubleValue(SKILLS, ARCHERY, SKILL_SHOT, MAX_DAMAGE); }
|
||||
|
||||
public double getDazeBonusDamage() { return getDoubleValue(SKILLS, ARCHERY, DAZE, BONUS_DAMAGE); }
|
||||
|
||||
public double getForceMultiplier() { return getDoubleValue(SKILLS, ARCHERY, FORCE_MULTIPLIER); }
|
||||
|
||||
/* AXES */
|
||||
public double getAxeMasteryRankDamageMultiplier() { return getDoubleValue(SKILLS, AXES, AXE_MASTERY, RANK_DAMAGE_MULTIPLIER); }
|
||||
|
||||
public double getCriticalStrikesPVPModifier() { return getDoubleValue(SKILLS, AXES, CRITICAL_STRIKES, PVP_MODIFIER); }
|
||||
public double getCriticalStrikesPVEModifier() { return getDoubleValue(SKILLS, AXES, CRITICAL_STRIKES, PVE_MODIFIER); }
|
||||
|
||||
public double getGreaterImpactChance() { return getDoubleValue(SKILLS, AXES, GREATER_IMPACT, CHANCE); }
|
||||
public double getGreaterImpactModifier() { return getDoubleValue(SKILLS, AXES, GREATER_IMPACT, KNOCKBACK_MODIFIER); }
|
||||
public double getGreaterImpactBonusDamage() { return getDoubleValue(SKILLS, AXES, GREATER_IMPACT, BONUS_DAMAGE); }
|
||||
|
||||
public int getArmorImpactIncreaseLevel() {
|
||||
int increaseLevel = getIntValue(SKILLS, AXES, ARMOR_IMPACT, INCREASE_LEVEL);
|
||||
|
||||
if(McmmoCore.isRetroModeEnabled())
|
||||
return increaseLevel * 10;
|
||||
|
||||
return increaseLevel;
|
||||
}
|
||||
|
||||
public double getImpactChance() { return getDoubleValue(SKILLS, AXES, ARMOR_IMPACT, CHANCE); }
|
||||
public double getArmorImpactMaxDurabilityDamage() { return getDoubleValue(SKILLS, AXES, ARMOR_IMPACT, MAX_PERCENTAGE_DURABILITY_DAMAGE); }
|
||||
|
||||
public double getSkullSplitterModifier() { return getDoubleValue(SKILLS, AXES, SKULL_SPLITTER, DAMAGE_MODIFIER); }
|
||||
|
||||
/* EXCAVATION */
|
||||
//Nothing to configure, everything is already configurable in config.yml
|
||||
|
||||
/* FISHING */
|
||||
public double getShakeChance(int rank) { return getDoubleValue(SKILLS, FISHING, SHAKE, CHANCE, RANK, String.valueOf(rank)); }
|
||||
public int getFishingVanillaXPModifier(int rank) { return getIntValue(SKILLS, FISHING, VANILLA_XPMULTIPLIER, RANK, String.valueOf(rank)); }
|
||||
public double getMasterAnglerBoatModifier() {return getDoubleValue(SKILLS, FISHING, MASTER_ANGLER, BOAT_MODIFIER); }
|
||||
public double getMasterAnglerBiomeModifier() {return getDoubleValue(SKILLS, FISHING, MASTER_ANGLER, BIOME_MODIFIER); }
|
||||
|
||||
/* HERBALISM */
|
||||
//public int getFarmerDietRankChange() { return getIntValue(SKILLS, ".Herbalism.FarmersDiet.RankChange"); }
|
||||
|
||||
//public int getGreenThumbStageChange() { return getIntValue(SKILLS, ".Herbalism.GreenThumb.StageChange"); }
|
||||
|
||||
/* MINING */
|
||||
public int getBlastMiningRankLevel(int rank) { return getIntValue(SKILLS, MINING, BLAST_MINING, RANK, LEVELS, RANK, String.valueOf(rank)); }
|
||||
public double getBlastDamageDecrease(int rank) { return getDoubleValue(SKILLS, MINING, BLAST_MINING, BLAST_DAMAGE_DECREASE, RANK, String.valueOf(rank)); }
|
||||
public double getOreBonus(int rank) { return getDoubleValue(SKILLS, MINING, BLAST_MINING, ORE_BONUS, RANK, String.valueOf(rank)); }
|
||||
public double getDebrisReduction(int rank) { return getDoubleValue(SKILLS, MINING, BLAST_MINING, DEBRIS_REDUCTION, RANK, String.valueOf(rank)); }
|
||||
public int getDropMultiplier(int rank) { return getIntValue(SKILLS, MINING, BLAST_MINING, DROP_MULTIPLIER, RANK, String.valueOf(rank)); }
|
||||
public double getBlastRadiusModifier(int rank) { return getDoubleValue(SKILLS, MINING, BLAST_MINING, BLAST_RADIUS, MODIFIER, RANK, String.valueOf(rank)); }
|
||||
|
||||
/* REPAIR */
|
||||
public double getRepairMasteryMaxBonus() { return getDoubleValue(SKILLS, REPAIR, REPAIR_MASTERY, MAX_BONUS_PERCENTAGE); }
|
||||
public int getRepairMasteryMaxLevel() { return getIntValue(SKILLS, REPAIR, REPAIR_MASTERY, MAX_BONUS_LEVEL); }
|
||||
|
||||
/* Arcane Forging */
|
||||
public boolean getArcaneForgingEnchantLossEnabled() { return getBooleanValue(SKILLS, REPAIR, ARCANE_FORGING, MAY_LOSE_ENCHANTS); }
|
||||
public double getArcaneForgingKeepEnchantsChance(int rank) { return getDoubleValue(SKILLS, REPAIR, ARCANE_FORGING, KEEP_ENCHANTS, CHANCE, RANK, String.valueOf(rank)); }
|
||||
|
||||
public boolean getArcaneForgingDowngradeEnabled() { return getBooleanValue(SKILLS, REPAIR, ARCANE_FORGING, DOWNGRADES_ENABLED); }
|
||||
public double getArcaneForgingDowngradeChance(int rank) { return getDoubleValue(SKILLS, REPAIR, ARCANE_FORGING, DOWNGRADES, CHANCE, RANK, String.valueOf(rank)); }
|
||||
|
||||
/* SALVAGE */
|
||||
|
||||
public boolean getArcaneSalvageEnchantDowngradeEnabled() { return getBooleanValue(SKILLS, SALVAGE, ARCANE_SALVAGE, ENCHANT_DOWNGRADE_ENABLED); }
|
||||
public boolean getArcaneSalvageEnchantLossEnabled() { return getBooleanValue(SKILLS, SALVAGE, ARCANE_SALVAGE, ENCHANT_LOSS_ENABLED); }
|
||||
|
||||
public double getArcaneSalvageExtractFullEnchantsChance(int rank) { return getDoubleValue(SKILLS, SALVAGE, ARCANE_SALVAGE, EXTRACT_FULL_ENCHANT, RANK, String.valueOf(rank)); }
|
||||
public double getArcaneSalvageExtractPartialEnchantsChance(int rank) { return getDoubleValue(SKILLS, SALVAGE, ARCANE_SALVAGE, EXTRACT_PARTIAL_ENCHANT, RANK, String.valueOf(rank)); }
|
||||
|
||||
/* SMELTING */
|
||||
public int getBurnModifierMaxLevel() { return getIntValue(SKILLS, SMELTING, FUEL_EFFICIENCY, MAX_BONUS_LEVEL); }
|
||||
public double getBurnTimeMultiplier() { return getDoubleValue(SKILLS, SMELTING, FUEL_EFFICIENCY, MULTIPLIER); }
|
||||
|
||||
public double getFluxMiningChance() { return getDoubleValue(SKILLS, SMELTING, FLUX, MINING, CHANCE); }
|
||||
|
||||
public int getSmeltingRankLevel(int rank) { return getIntValue(SKILLS, SMELTING, RANK, LEVELS, RANK, String.valueOf(rank)); }
|
||||
|
||||
public int getSmeltingVanillaXPBoostMultiplier(int rank) { return getIntValue(SKILLS, SMELTING, VANILLA_XPMULTIPLIER, RANK, String.valueOf(rank)); }
|
||||
|
||||
/* SWORDS */
|
||||
public double getRuptureDamagePlayer() { return getDoubleValue(SKILLS, SWORDS, RUPTURE, DAMAGE_PLAYER); }
|
||||
public double getRuptureDamageMobs() { return getDoubleValue(SKILLS, SWORDS, RUPTURE, DAMAGE_MOBS); }
|
||||
|
||||
public int getRuptureMaxTicks() { return getIntValue(SKILLS, SWORDS, RUPTURE, MAX_TICKS); }
|
||||
public int getRuptureBaseTicks() { return getIntValue(SKILLS, SWORDS, RUPTURE, BASE_TICKS); }
|
||||
|
||||
public double getCounterModifier() { return getDoubleValue(SKILLS, SWORDS, COUNTER_ATTACK, DAMAGE_MODIFIER); }
|
||||
|
||||
public double getSerratedStrikesModifier() { return getDoubleValue(SKILLS, SWORDS, SERRATED_STRIKES, DAMAGE_MODIFIER); }
|
||||
public int getSerratedStrikesTicks() { return getIntValue(SKILLS, SWORDS, SERRATED_STRIKES, RUPTURE, TICKS); }
|
||||
|
||||
/* TAMING */
|
||||
public double getGoreModifier() { return getDoubleValue(SKILLS, TAMING, GORE, MODIFIER); }
|
||||
public double getFastFoodChance() { return getDoubleValue(SKILLS, TAMING, FAST_FOOD_SERVICE, CHANCE); }
|
||||
public double getPummelChance() { return getDoubleValue(SKILLS, TAMING, PUMMEL, CHANCE); }
|
||||
public double getThickFurModifier() { return getDoubleValue(SKILLS, TAMING, THICK_FUR, MODIFIER); }
|
||||
public double getShockProofModifier() { return getDoubleValue(SKILLS, TAMING, SHOCK_PROOF, MODIFIER); }
|
||||
|
||||
public double getSharpenedClawsBonus() { return getDoubleValue(SKILLS, TAMING, SHARPENED_CLAWS, BONUS); }
|
||||
|
||||
public double getMinHorseJumpStrength() { return getDoubleValue(SKILLS, TAMING, CALL_OF_THE_WILD, MIN_HORSE_JUMP_STRENGTH); }
|
||||
public double getMaxHorseJumpStrength() { return getDoubleValue(SKILLS, TAMING, CALL_OF_THE_WILD, MAX_HORSE_JUMP_STRENGTH); }
|
||||
|
||||
/* UNARMED */
|
||||
public boolean getDisarmProtected() { return getBooleanValue(SKILLS, UNARMED, DISARM, ANTI_THEFT); }
|
||||
|
||||
/* WOODCUTTING */
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.skills.child.FamilyTree;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class ChildConfig extends AutoUpdateConfigLoader {
|
||||
public ChildConfig() {
|
||||
super("child.yml");
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
config.setDefaults(YamlConfiguration.loadConfiguration(plugin.getResourceAsReader("child.yml")));
|
||||
|
||||
FamilyTree.clearRegistrations(); // when reloading, need to clear statics
|
||||
|
||||
for (PrimarySkillType skill : PrimarySkillType.CHILD_SKILLS) {
|
||||
plugin.debug("Finding parents of " + skill.name());
|
||||
|
||||
EnumSet<PrimarySkillType> parentSkills = EnumSet.noneOf(PrimarySkillType.class);
|
||||
boolean useDefaults = false; // If we had an error we back out and use defaults
|
||||
|
||||
for (String name : config.getStringList(StringUtils.getCapitalized(skill.name()))) {
|
||||
try {
|
||||
PrimarySkillType parentSkill = PrimarySkillType.valueOf(name.toUpperCase());
|
||||
FamilyTree.enforceNotChildSkill(parentSkill);
|
||||
parentSkills.add(parentSkill);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
plugin.getLogger().warning(name + " is not a valid skill type, or is a child skill!");
|
||||
useDefaults = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (useDefaults) {
|
||||
parentSkills.clear();
|
||||
for (String name : config.getDefaults().getStringList(StringUtils.getCapitalized(skill.name()))) {
|
||||
/* We do less checks in here because it's from inside our jar.
|
||||
* If they're dedicated enough to have modified it, they can have the errors it may produce.
|
||||
* Alternatively, this can be used to allow child skills to be parent skills, provided there are no circular dependencies this is an advanced sort of configuration.
|
||||
*/
|
||||
parentSkills.add(PrimarySkillType.valueOf(name.toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
// Register them
|
||||
for (PrimarySkillType parentSkill : parentSkills) {
|
||||
plugin.debug("Registering " + parentSkill.name() + " as parent of " + skill.name());
|
||||
FamilyTree.registerParent(skill, parentSkill);
|
||||
}
|
||||
}
|
||||
|
||||
FamilyTree.closeRegistration();
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
/**
|
||||
* This class is used to define settings for upgrading EXTREMELY OLD versions of mcMMO to newer versions
|
||||
* It could probably be deleted
|
||||
*/
|
||||
public class ChunkConversionOptions {
|
||||
private static final boolean chunkletsEnabled = true;
|
||||
private static final int conversionRate = 1;
|
||||
private static final boolean useEnchantmentBuffs = true;
|
||||
private static final int uuidConvertAmount = 5;
|
||||
private static final int mojangRateLimit = 50000;
|
||||
private static final long mojangLimitPeriod = 600000;
|
||||
|
||||
public static boolean getChunkletsEnabled() {
|
||||
return chunkletsEnabled;
|
||||
}
|
||||
|
||||
public static int getConversionRate() {
|
||||
return conversionRate;
|
||||
}
|
||||
|
||||
public static boolean useEnchantmentBuffs() {
|
||||
return useEnchantmentBuffs;
|
||||
}
|
||||
|
||||
public static int getUUIDConvertAmount() {
|
||||
return uuidConvertAmount;
|
||||
}
|
||||
|
||||
public static int getMojangRateLimit() {
|
||||
return mojangRateLimit;
|
||||
}
|
||||
|
||||
public static long getMojangLimitPeriod() {
|
||||
return mojangLimitPeriod;
|
||||
}
|
||||
}
|
338
core/src/main/java/com/gmail/nossr50/core/config/Config.java
Normal file
338
core/src/main/java/com/gmail/nossr50/core/config/Config.java
Normal file
@ -0,0 +1,338 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.google.common.io.Files;
|
||||
import ninja.leaping.configurate.ConfigurationNode;
|
||||
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Handles loading and cacheing configuration settings from a configurable compatible config file
|
||||
*/
|
||||
//@ConfigSerializable
|
||||
public abstract class Config implements VersionedConfig, Unload {
|
||||
|
||||
/* SETTINGS */
|
||||
private boolean mergeNewKeys;
|
||||
|
||||
/* PATH VARS */
|
||||
|
||||
public final File DIRECTORY_DATA_FOLDER; //Directory that the file is in
|
||||
public final String FILE_RELATIVE_PATH; //Relative Path to the file
|
||||
protected final String DIRECTORY_DEFAULTS = "defaults";
|
||||
|
||||
/* LOADERS */
|
||||
|
||||
private YAMLConfigurationLoader defaultCopyLoader;
|
||||
private YAMLConfigurationLoader userCopyLoader;
|
||||
|
||||
/* CONFIG FILES */
|
||||
|
||||
private File resourceConfigCopy; //Copy of the default config from the JAR (file is copied so that admins can easily compare to defaults)
|
||||
private File resourceUserCopy; //File in the /$MCMMO_ROOT/mcMMO/ directory that may contain user edited settings
|
||||
|
||||
/* ROOT NODES */
|
||||
|
||||
private ConfigurationNode userRootNode = null;
|
||||
private ConfigurationNode defaultRootNode = null;
|
||||
|
||||
/* CONFIG MANAGER */
|
||||
private ConfigurationLoader<CommentedConfigurationNode> configManager;
|
||||
|
||||
public Config(String pathToParentFolder, String relativePath, boolean mergeNewKeys) {
|
||||
//TODO: Check if this works...
|
||||
this(new File(pathToParentFolder), relativePath, mergeNewKeys);
|
||||
System.out.println("mcMMO Debug: Don't forget to check if loading config file by string instead of File works...");
|
||||
}
|
||||
|
||||
public Config(File pathToParentFolder, String relativePath, boolean mergeNewKeys) {
|
||||
/*
|
||||
* These must be at the top
|
||||
*/
|
||||
this.mergeNewKeys = mergeNewKeys; //Whether or not we add new keys when they are found
|
||||
mkdirDefaults(); // Make our default config dir
|
||||
DIRECTORY_DATA_FOLDER = pathToParentFolder; //Data Folder for our plugin
|
||||
FILE_RELATIVE_PATH = relativePath; //Relative path to config from a parent folder
|
||||
|
||||
//Attempt IO Operations
|
||||
try {
|
||||
//Makes sure we have valid Files corresponding to this config
|
||||
initConfigFiles();
|
||||
|
||||
//Init MainConfig Loaders
|
||||
initConfigLoaders();
|
||||
|
||||
//Load MainConfig Nodes
|
||||
loadConfig();
|
||||
|
||||
//Attempt to update user file, and then load it into memory
|
||||
readConfig();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default copy File and the user config File
|
||||
* @throws IOException
|
||||
*/
|
||||
private void initConfigFiles() throws IOException {
|
||||
//Init our config copy
|
||||
resourceConfigCopy = initDefaultConfig();
|
||||
|
||||
//Init the user file
|
||||
resourceUserCopy = initUserConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the root node for the default config File and user config File
|
||||
*/
|
||||
private void loadConfig()
|
||||
{
|
||||
try {
|
||||
final ConfigurationNode defaultConfig = this.defaultCopyLoader.load();
|
||||
defaultRootNode = defaultConfig;
|
||||
|
||||
final ConfigurationNode userConfig = this.userCopyLoader.load();
|
||||
userRootNode = userConfig;
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the YAMLConfigurationLoaders for this config
|
||||
*/
|
||||
private void initConfigLoaders()
|
||||
{
|
||||
this.defaultCopyLoader = YAMLConfigurationLoader.builder().setPath(resourceConfigCopy.toPath()).setFlowStyle(DumperOptions.FlowStyle.BLOCK).build();
|
||||
this.userCopyLoader = YAMLConfigurationLoader.builder().setPath(resourceUserCopy.toPath()).setFlowStyle(DumperOptions.FlowStyle.FLOW).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a new file from the JAR to the defaults directory and uses that new file to initialize our resourceConfigCopy
|
||||
* @see Config#resourceConfigCopy
|
||||
* @throws IOException
|
||||
*/
|
||||
private File initDefaultConfig() throws IOException {
|
||||
return copyDefaultFromJar(getDefaultConfigCopyRelativePath(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attemps to load the config file if it exists, if it doesn't it copies a new one from within the JAR
|
||||
* @return user config File
|
||||
* @see Config#resourceUserCopy
|
||||
* @throws IOException
|
||||
*/
|
||||
private File initUserConfig() throws IOException {
|
||||
File userCopy = new File(DIRECTORY_DATA_FOLDER, FILE_RELATIVE_PATH); //Load the user file;
|
||||
|
||||
if(userCopy.exists())
|
||||
{
|
||||
// Yay
|
||||
return userCopy;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If it's gone we copy default files
|
||||
//Note that we don't copy the values from the default copy put in /defaults/ that file exists only as a reference to admins and is unreliable
|
||||
return copyDefaultFromJar(FILE_RELATIVE_PATH, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to make a new config file at a specified relative output path inside the data directory by copying the matching file found in that same relative path within the JAR
|
||||
* @param relativeOutputPath the path to the output file
|
||||
* @param deleteOld whether or not to delete the existing output file on disk
|
||||
* @return a copy of the default config within the JAR
|
||||
* @throws IOException
|
||||
*/
|
||||
private File copyDefaultFromJar(String relativeOutputPath, boolean deleteOld) throws IOException
|
||||
{
|
||||
/*
|
||||
* Gen a Default config from inside the JAR
|
||||
*/
|
||||
McmmoCore.getLogger().info("Preparing to copy internal resource file (in JAR) - "+FILE_RELATIVE_PATH);
|
||||
InputStream inputStream = McmmoCore.getResource(FILE_RELATIVE_PATH);
|
||||
|
||||
byte[] buffer = new byte[inputStream.available()];
|
||||
inputStream.read(buffer);
|
||||
|
||||
//This is a copy of the default file, which we will overwrite every time mcMMO loads
|
||||
File targetFile = new File(DIRECTORY_DATA_FOLDER, relativeOutputPath);
|
||||
|
||||
//Wipe old default file on disk
|
||||
if (targetFile.exists() && deleteOld)
|
||||
{
|
||||
McmmoCore.getLogger().info("Updating file " + relativeOutputPath);
|
||||
targetFile.delete(); //Necessary?
|
||||
}
|
||||
|
||||
if(!targetFile.exists())
|
||||
{
|
||||
targetFile.getParentFile().mkdirs();
|
||||
targetFile.createNewFile(); //New File Boys
|
||||
}
|
||||
|
||||
Files.write(buffer, targetFile);
|
||||
McmmoCore.getLogger().info("Created config file - " + relativeOutputPath);
|
||||
|
||||
inputStream.close(); //Close the input stream
|
||||
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the defaults directory
|
||||
* @return the path to the defaults directory
|
||||
*/
|
||||
private String getDefaultConfigCopyRelativePath() {
|
||||
return DIRECTORY_DEFAULTS + File.separator + FILE_RELATIVE_PATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the defaults directory
|
||||
*/
|
||||
private void mkdirDefaults() {
|
||||
//Make Default Subdirectory
|
||||
File defaultsDir = new File (DIRECTORY_DATA_FOLDER, "defaults");
|
||||
|
||||
if(!defaultsDir.exists())
|
||||
defaultsDir.mkdir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configs are versioned based on when they had significant changes to keys
|
||||
* @return current MainConfig Version String
|
||||
*/
|
||||
public String getVersion()
|
||||
{
|
||||
return String.valueOf(getConfigVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read the loaded config file
|
||||
* MainConfig will have any necessary updates applied
|
||||
* MainConfig will be compared to the default config to see if it is missing any nodes
|
||||
* MainConfig will have any missing nodes inserted with their default value
|
||||
*/
|
||||
public void readConfig() {
|
||||
McmmoCore.getLogger().info("Attempting to read " + FILE_RELATIVE_PATH + ".");
|
||||
|
||||
int version = this.userRootNode.getNode("ConfigVersion").getInt();
|
||||
McmmoCore.getLogger().info(FILE_RELATIVE_PATH + " version is " + version);
|
||||
|
||||
//Update our config
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the users config file to the default and adds any missing nodes and applies any necessary updates
|
||||
*/
|
||||
private void updateConfig()
|
||||
{
|
||||
McmmoCore.getLogger().info(defaultRootNode.getChildrenMap().size() +" items in default children map");
|
||||
McmmoCore.getLogger().info(userRootNode.getChildrenMap().size() +" items in default root map");
|
||||
|
||||
// Merge Values from default
|
||||
if(mergeNewKeys)
|
||||
userRootNode = userRootNode.mergeValuesFrom(defaultRootNode);
|
||||
|
||||
removeOldKeys();
|
||||
|
||||
// Update config version
|
||||
updateConfigVersion();
|
||||
|
||||
//Attempt to save
|
||||
try {
|
||||
saveUserCopy();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state information of the config to the users copy (which they may edit)
|
||||
* @throws IOException
|
||||
*/
|
||||
private void saveUserCopy() throws IOException
|
||||
{
|
||||
McmmoCore.getLogger().info("Saving new node");
|
||||
userCopyLoader.save(userRootNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs any necessary operations to update this config
|
||||
*/
|
||||
private void updateConfigVersion() {
|
||||
// Set a version for our config
|
||||
this.userRootNode.getNode("ConfigVersion").setValue(getConfigVersion());
|
||||
McmmoCore.getLogger().info("Updated config to ["+getConfigVersion()+"] - " + FILE_RELATIVE_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root node of this config
|
||||
* @return the root node of this config
|
||||
*/
|
||||
protected ConfigurationNode getUserRootNode() {
|
||||
return userRootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs an int from the specified node
|
||||
* @param path
|
||||
* @return the int from the node, null references will zero initialize
|
||||
*/
|
||||
public int getIntValue(String... path)
|
||||
{
|
||||
return userRootNode.getNode(path).getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a double from the specified node
|
||||
* @param path
|
||||
* @return the double from the node, null references will zero initialize
|
||||
*/
|
||||
public double getDoubleValue(String... path)
|
||||
{
|
||||
return userRootNode.getNode(path).getDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a boolean from the specified node
|
||||
* @param path
|
||||
* @return the boolean from the node, null references will zero initialize
|
||||
*/
|
||||
public boolean getBooleanValue(String... path)
|
||||
{
|
||||
return userRootNode.getNode(path).getBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs a string from the specified node
|
||||
* @param path
|
||||
* @return the string from the node, null references will zero initialize
|
||||
*/
|
||||
public String getStringValue(String... path)
|
||||
{
|
||||
return userRootNode.getNode(path).getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a node exists in the user's config file
|
||||
* @param path path to the node
|
||||
* @return true if the node exists
|
||||
*/
|
||||
public boolean hasNode(String... path) {
|
||||
return (userRootNode.getNode(path) != null);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ConfigCollection<T> {
|
||||
Collection<T> getLoadedCollection();
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Represents a config file that registers keys after its initialized
|
||||
*/
|
||||
public abstract class ConfigCollections extends Config implements RegistersKeys, ConfigCollection {
|
||||
|
||||
public ConfigCollections(String pathToParentFolder, String relativePath, boolean mergeNewKeys) {
|
||||
super(pathToParentFolder, relativePath, mergeNewKeys);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
public ConfigCollections(File pathToParentFolder, String relativePath, boolean mergeNewKeys) {
|
||||
super(pathToParentFolder, relativePath, mergeNewKeys);
|
||||
loadKeys();
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is used for config files that validate their entries
|
||||
*/
|
||||
public abstract class ConfigValidated extends Config implements DefaultKeys {
|
||||
public ConfigValidated(String parentFolderPath, String relativePath, boolean mergeNewKeys)
|
||||
{
|
||||
super(parentFolderPath, relativePath, mergeNewKeys);
|
||||
validateEntries();
|
||||
}
|
||||
|
||||
public ConfigValidated(File parentFolderFile, String relativePath, boolean mergeNewKeys)
|
||||
{
|
||||
super(parentFolderFile, relativePath, mergeNewKeys);
|
||||
validateEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints all errors found when validating the config
|
||||
*/
|
||||
private void validateEntries()
|
||||
{
|
||||
/*
|
||||
* Print Errors about Keys
|
||||
*/
|
||||
|
||||
List<String> validKeyErrors = validateKeys(); // Validate Keys
|
||||
|
||||
if(validKeyErrors != null && validKeyErrors.size() > 0)
|
||||
{
|
||||
for(String error : validKeyErrors)
|
||||
{
|
||||
McmmoCore.getLogger().severe(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.skills.subskills.AbstractSubSkill;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
public class CoreSkillsConfig extends Config {
|
||||
private static CoreSkillsConfig instance;
|
||||
|
||||
public CoreSkillsConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(),"coreskills.yml", true);
|
||||
}
|
||||
|
||||
public static CoreSkillsConfig getInstance() {
|
||||
if (instance == null)
|
||||
return new CoreSkillsConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skill Settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Whether or not a skill is enabled
|
||||
* Defaults true
|
||||
*
|
||||
* @param abstractSubSkill SubSkill definition to check
|
||||
* @return true if subskill is enabled
|
||||
*/
|
||||
public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill) {
|
||||
return getBooleanValue(StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill().toString()) + "." + abstractSubSkill.getConfigKeyName() + ".Enabled", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this primary skill is enabled
|
||||
*
|
||||
* @param primarySkillType target primary skill
|
||||
* @return true if enabled
|
||||
*/
|
||||
public boolean isPrimarySkillEnabled(PrimarySkillType primarySkillType) {
|
||||
return getBooleanValue(StringUtils.getCapitalized(primarySkillType.toString()) + ".Enabled", true);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is for config validation
|
||||
*/
|
||||
public interface DefaultKeys {
|
||||
List<String> validateKeys();
|
||||
}
|
1042
core/src/main/java/com/gmail/nossr50/core/config/MainConfig.java
Normal file
1042
core/src/main/java/com/gmail/nossr50/core/config/MainConfig.java
Normal file
File diff suppressed because it is too large
Load Diff
124
core/src/main/java/com/gmail/nossr50/core/config/RankConfig.java
Normal file
124
core/src/main/java/com/gmail/nossr50/core/config/RankConfig.java
Normal file
@ -0,0 +1,124 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.skills.SubSkillType;
|
||||
import com.gmail.nossr50.core.skills.subskills.AbstractSubSkill;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RankConfig extends ConfigValidated {
|
||||
private static RankConfig instance;
|
||||
|
||||
public RankConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(),"skillranks.yml", true);
|
||||
this.instance = this;
|
||||
}
|
||||
|
||||
public static RankConfig getInstance() {
|
||||
if (instance == null)
|
||||
return new RankConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateKeys() {
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/*
|
||||
* In the future this method will check keys for all skills, but for now it only checks overhauled skills
|
||||
*/
|
||||
checkKeys(reason);
|
||||
|
||||
return reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
*
|
||||
* @param subSkillType target subskill
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank) {
|
||||
String key = subSkillType.getRankConfigAddress();
|
||||
|
||||
return findRankByRootAddress(rank, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
*
|
||||
* @param abstractSubSkill target subskill
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) {
|
||||
String key = abstractSubSkill.getPrimaryKeyName() + "." + abstractSubSkill.getConfigKeyName();
|
||||
|
||||
return findRankByRootAddress(rank, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unlock level for a subskill depending on the gamemode
|
||||
*
|
||||
* @param key root address of the subskill in the rankskills.yml file
|
||||
* @param rank the rank we are checking
|
||||
* @return the level requirement for a subskill at this particular rank
|
||||
*/
|
||||
private int findRankByRootAddress(int rank, String key) {
|
||||
String scalingKey = MainConfig.getInstance().getIsRetroMode() ? ".RetroMode." : ".Standard.";
|
||||
|
||||
String targetRank = "Rank_" + rank;
|
||||
|
||||
key += scalingKey;
|
||||
key += targetRank;
|
||||
|
||||
return getIntValue(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for valid keys for subskill ranks
|
||||
*/
|
||||
private void checkKeys(List<String> reasons) {
|
||||
//For now we will only check ranks of stuff I've overhauled
|
||||
for (SubSkillType subSkillType : SubSkillType.values()) {
|
||||
//Keeping track of the rank requirements and making sure there are no logical errors
|
||||
int curRank = 0;
|
||||
int prevRank = 0;
|
||||
|
||||
for (int x = 0; x < subSkillType.getNumRanks(); x++) {
|
||||
if (curRank > 0)
|
||||
prevRank = curRank;
|
||||
|
||||
curRank = getSubSkillUnlockLevel(subSkillType, x);
|
||||
|
||||
//Do we really care if its below 0? Probably not
|
||||
if (curRank < 0) {
|
||||
reasons.add(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_" + curRank + ".LevelReq should be above or equal to 0!");
|
||||
}
|
||||
|
||||
if (prevRank > curRank) {
|
||||
//We're going to allow this but we're going to warn them
|
||||
plugin.getLogger().info("You have the ranks for the subskill " + subSkillType.toString() + " set up poorly, sequential ranks should have ascending requirements");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
/**
|
||||
* A class that registers keys
|
||||
*/
|
||||
public interface RegistersKeys {
|
||||
/**
|
||||
* Loads up keys
|
||||
*/
|
||||
void loadKeys();
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.util.sounds.SoundType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SoundConfig extends ConfigValidated {
|
||||
private static SoundConfig instance;
|
||||
|
||||
public SoundConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), "sounds.yml", true);
|
||||
this.instance = this;
|
||||
}
|
||||
|
||||
public static SoundConfig getInstance() {
|
||||
if (instance == null)
|
||||
return new SoundConfig();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateKeys() {
|
||||
ArrayList<String> reasons = new ArrayList<>();
|
||||
|
||||
for (SoundType soundType : SoundType.values()) {
|
||||
if (getDoubleValue("Sounds." + soundType.toString() + ".Volume") < 0) {
|
||||
reasons.add("[mcMMO] Sound volume cannot be below 0 for " + soundType.toString());
|
||||
}
|
||||
|
||||
//Sounds with custom pitching don't use pitch values
|
||||
if (!soundType.usesCustomPitch()) {
|
||||
if (getDoubleValue("Sounds." + soundType.toString() + ".Pitch") < 0) {
|
||||
reasons.add("[mcMMO] Sound pitch cannot be below 0 for " + soundType.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reasons;
|
||||
}
|
||||
|
||||
public float getMasterVolume() {
|
||||
return (float) getDoubleValue("Sounds.MasterVolume", 1.0);
|
||||
}
|
||||
|
||||
public float getVolume(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Volume";
|
||||
return (float) getDoubleValue(key);
|
||||
}
|
||||
|
||||
public float getPitch(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Pitch";
|
||||
return (float) getDoubleValue(key);
|
||||
}
|
||||
|
||||
public boolean getIsEnabled(SoundType soundType) {
|
||||
String key = "Sounds." + soundType.toString() + ".Enabled";
|
||||
return getBooleanValue(key, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
/**
|
||||
* Unloads values, sort of like a constructor
|
||||
*/
|
||||
public interface Unload {
|
||||
void unload();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
/**
|
||||
* Represents a config that is version checked
|
||||
*/
|
||||
public interface VersionedConfig {
|
||||
/**
|
||||
* The version of this config
|
||||
* @return
|
||||
*/
|
||||
double getConfigVersion();
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.gmail.nossr50.core.config;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Blacklist certain features in certain worlds
|
||||
*/
|
||||
public class WorldBlacklist {
|
||||
private static ArrayList<String> blacklist;
|
||||
private final String blackListFileName = "world_blacklist.txt";
|
||||
|
||||
public WorldBlacklist() {
|
||||
blacklist = new ArrayList<>();
|
||||
init();
|
||||
}
|
||||
|
||||
public static boolean isWorldBlacklisted(World world) {
|
||||
|
||||
for (String s : blacklist) {
|
||||
if (world.getName().equalsIgnoreCase(s))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
//Make the blacklist file if it doesn't exist
|
||||
//TODO: Check if this works
|
||||
File blackListFile = new File(McmmoCore.getDataFolderPath().getAbsoluteFile() + File.separator + blackListFileName);
|
||||
|
||||
try {
|
||||
if (!blackListFile.exists())
|
||||
blackListFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//Load up the blacklist
|
||||
loadBlacklist(blackListFile);
|
||||
//registerFlags();
|
||||
}
|
||||
|
||||
private void loadBlacklist(File blackListFile) {
|
||||
try {
|
||||
FileReader fileReader = new FileReader(blackListFile);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
|
||||
String currentLine;
|
||||
|
||||
while ((currentLine = bufferedReader.readLine()) != null) {
|
||||
if (currentLine.length() == 0)
|
||||
continue;
|
||||
|
||||
if (!blacklist.contains(currentLine))
|
||||
blacklist.add(currentLine);
|
||||
}
|
||||
|
||||
//Close readers
|
||||
bufferedReader.close();
|
||||
fileReader.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
McmmoCore.getLogger().info(blacklist.size() + " entries in mcMMO World Blacklist");
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package com.gmail.nossr50.core.config.collectionconfigs;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.ConfigCollection;
|
||||
import com.gmail.nossr50.core.config.ConfigCollections;
|
||||
import com.gmail.nossr50.core.skills.child.salvage.salvageables.Salvageable;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.Repairable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a collection of config files that serve a similar purpose
|
||||
* For example, files named repair.*.yml are all loaded into memory, this lets admins keep their config files clean
|
||||
*
|
||||
* To be honest I'm not sure how many people make use of this system, but I'm keeping it since its been in mcMMO for like 6+ years
|
||||
*/
|
||||
public final class MultiConfigManager {
|
||||
|
||||
public static final String DEFAULT_MULTICONFIG_FILENAME_SUFFIX = ".vanilla.yml";
|
||||
|
||||
//Configs
|
||||
public RepairConfig vanillaRepairConfig; //This is the main config file that mcMMO will copy out
|
||||
public SalvageConfig vanillaSalvageConfig;
|
||||
|
||||
private static List<Repairable> repairables;
|
||||
private static List<Salvageable> salvageables;
|
||||
|
||||
public MultiConfigManager(String fileNamePrefix)
|
||||
{
|
||||
//init Collections
|
||||
repairables = new ArrayList<>();
|
||||
salvageables = new ArrayList<>();
|
||||
|
||||
//init vanilla configs
|
||||
vanillaRepairConfig = new RepairConfig(getVanillaConfigName("repair"));
|
||||
vanillaSalvageConfig = new SalvageConfig(getVanillaConfigName("salvage"));
|
||||
|
||||
//add valid vanilla collections to main collection
|
||||
repairables.addAll(vanillaRepairConfig.getLoadedCollection());
|
||||
salvageables.addAll(vanillaSalvageConfig.getLoadedCollection());
|
||||
|
||||
//add valid custom collections to main collection
|
||||
loadCustomCollections("repair", repairables, RepairConfig.class);
|
||||
loadCustomCollections("salvage", salvageables, SalvageConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* mcMMO allows collection config files to be named things like repair.whatevernameyouwanthere.yml and so on,
|
||||
* these files are treated in the same way as the vanilla file. They serve the purpose of organization
|
||||
* @param configPrefix the prefix of the file name, for example "repair", "salvage", etc
|
||||
* @param collection the collection that will be added to
|
||||
*/
|
||||
public void loadCustomCollections(String configPrefix, Collection<?> collection, Class<? extends ConfigCollection> configClass)
|
||||
{
|
||||
String vanillaConfigFileName = getVanillaConfigName(configPrefix);
|
||||
|
||||
//Find other files
|
||||
Pattern pattern = Pattern.compile(configPrefix+"\\.(?:.+)\\.yml");
|
||||
File dataFolder = McmmoCore.getDataFolderPath();
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
//Vanilla Config is already loaded
|
||||
if(fileName.equalsIgnoreCase(vanillaConfigFileName))
|
||||
continue;
|
||||
|
||||
//Find files that match the pattern
|
||||
if (!pattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Init file
|
||||
File currentFile = new File(dataFolder, fileName);
|
||||
|
||||
//Make sure its not a directory (needed?)
|
||||
if(currentFile.isDirectory())
|
||||
continue;
|
||||
|
||||
|
||||
try {
|
||||
ConfigCollections customConfig = configClass.getClass().getConstructor(fileName).newInstance();
|
||||
collection.addAll(customConfig.getLoadedCollection());
|
||||
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String getVanillaConfigName(String configPrefix)
|
||||
{
|
||||
return configPrefix+DEFAULT_MULTICONFIG_FILENAME_SUFFIX;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
package com.gmail.nossr50.core.config.collectionconfigs;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.ConfigCollections;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.ConfigItemCategory;
|
||||
import com.gmail.nossr50.core.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.core.util.InvalidItemException;
|
||||
import com.gmail.nossr50.core.util.ItemUtils;
|
||||
import com.gmail.nossr50.core.util.skills.SkillUtils;
|
||||
import ninja.leaping.configurate.ConfigurationNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This config
|
||||
*/
|
||||
public class RepairConfig extends ConfigCollections {
|
||||
private List<Repairable> repairables;
|
||||
|
||||
public RepairConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), fileName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
repairables = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection getLoadedCollection() {
|
||||
return repairables == null ? new ArrayList<Repairable>() : repairables;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadKeys() {
|
||||
repairables = new ArrayList<Repairable>();
|
||||
|
||||
ConfigurationNode repairablesNode = getUserRootNode().getNode("Repairables");
|
||||
List<? extends ConfigurationNode> repairablesNodeChildrenList = repairablesNode.getChildrenList();
|
||||
Iterator<? extends ConfigurationNode> configIter = repairablesNodeChildrenList.iterator();
|
||||
|
||||
for(Iterator<? extends ConfigurationNode> i = repairablesNodeChildrenList.iterator(); i.hasNext();)
|
||||
{
|
||||
ConfigurationNode iterNode = i.next();
|
||||
//TODO: Verify that this is getting the key
|
||||
String key = iterNode.getKey().toString(); //Get the String of the node
|
||||
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
try {
|
||||
// ItemStack Material
|
||||
ConfigItemCategory configItemCategory = ItemUtils.matchItemType(key);
|
||||
} catch (InvalidItemException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (itemType == null) {
|
||||
reason.add("Invalid material: " + key);
|
||||
}
|
||||
|
||||
// Repair Material Type
|
||||
MaterialType repairMaterialType = MaterialType.OTHER;
|
||||
String repairMaterialTypeString = getStringValue("Repairables." + key + ".MaterialType", "OTHER");
|
||||
|
||||
if (!config.contains("Repairables." + key + ".MaterialType") && itemType != null) {
|
||||
ItemStack repairItem = ItemStack.makeNew(itemType);
|
||||
|
||||
if (ItemUtils.isWoodTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.WOOD;
|
||||
} else if (ItemUtils.isStoneTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.STONE;
|
||||
} else if (ItemUtils.isStringTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.STRING;
|
||||
} else if (ItemUtils.isLeatherArmor(repairItem)) {
|
||||
repairMaterialType = MaterialType.LEATHER;
|
||||
} else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.IRON;
|
||||
} else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.GOLD;
|
||||
} else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
|
||||
repairMaterialType = MaterialType.DIAMOND;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
repairMaterialType = MaterialType.valueOf(repairMaterialTypeString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid MaterialType of " + repairMaterialTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
// Repair Material
|
||||
String repairMaterialName = getStringValue("Repairables." + key + ".RepairMaterial");
|
||||
Material repairMaterial = (repairMaterialName == null ? repairMaterialType.getDefaultMaterial() : Material.matchMaterial(repairMaterialName));
|
||||
|
||||
if (repairMaterial == null) {
|
||||
reason.add(key + " has an invalid repair material: " + repairMaterialName);
|
||||
}
|
||||
|
||||
// Maximum Durability
|
||||
short maximumDurability = (itemType != null ? itemType.getMaxDurability() : (short) getIntValue("Repairables." + key + ".MaximumDurability"));
|
||||
|
||||
if (maximumDurability <= 0) {
|
||||
maximumDurability = (short) getIntValue("Repairables." + key + ".MaximumDurability");
|
||||
}
|
||||
|
||||
if (maximumDurability <= 0) {
|
||||
reason.add("Maximum durability of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
// ItemStack Type
|
||||
ConfigItemCategory repairConfigItemCategory = ConfigItemCategory.OTHER;
|
||||
String repairItemTypeString = getStringValue("Repairables." + key + ".ItemType", "OTHER");
|
||||
|
||||
if (!config.contains("Repairables." + key + ".ItemType") && itemType != null) {
|
||||
ItemStack repairItem = new ItemStack(itemType);
|
||||
|
||||
if (ItemUtils.isMinecraftTool(repairItem)) {
|
||||
repairConfigItemCategory = ConfigItemCategory.TOOL;
|
||||
} else if (ItemUtils.isArmor(repairItem)) {
|
||||
repairConfigItemCategory = ConfigItemCategory.ARMOR;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
repairConfigItemCategory = ConfigItemCategory.valueOf(repairItemTypeString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid ItemType of " + repairItemTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
byte repairMetadata = (byte) getIntValue("Repairables." + key + ".RepairMaterialMetadata", -1);
|
||||
int minimumLevel = getIntValue("Repairables." + key + ".MinimumLevel");
|
||||
double xpMultiplier = getDoubleValue("Repairables." + key + ".XpMultiplier", 1);
|
||||
|
||||
if (minimumLevel < 0) {
|
||||
reason.add(key + " has an invalid MinimumLevel of " + minimumLevel);
|
||||
}
|
||||
|
||||
// Minimum Quantity
|
||||
int minimumQuantity = (itemType != null ? SkillUtils.getRepairAndSalvageQuantities(new ItemStack(itemType), repairMaterial, repairMetadata) : getIntValue("Repairables." + key + ".MinimumQuantity", 2));
|
||||
|
||||
if (minimumQuantity <= 0 && itemType != null) {
|
||||
minimumQuantity = getIntValue("Repairables." + key + ".MinimumQuantity", 2);
|
||||
}
|
||||
|
||||
if (minimumQuantity <= 0) {
|
||||
reason.add("Minimum quantity of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
if (noErrorsInRepairable(reason)) {
|
||||
Repairable repairable = RepairableFactory.getRepairable(itemType, repairMaterial, repairMetadata, minimumLevel, minimumQuantity, maximumDurability, repairConfigItemCategory, repairMaterialType, xpMultiplier);
|
||||
repairables.add(repairable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if there are any errors for this repairable and if there are reports them to console
|
||||
* @param issues errors related to loading a repairable
|
||||
* @return returns true if there are no errors for this repairable
|
||||
*/
|
||||
private boolean noErrorsInRepairable(List<String> issues) {
|
||||
for (String issue : issues) {
|
||||
McmmoCore.getLogger().warning(issue);
|
||||
}
|
||||
|
||||
return issues.isEmpty();
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package com.gmail.nossr50.core.config.collectionconfigs;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.config.ConfigCollection;
|
||||
import com.gmail.nossr50.core.config.ConfigCollections;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.skills.child.salvage.salvageables.Salvageable;
|
||||
import com.gmail.nossr50.core.skills.child.salvage.salvageables.SalvageableFactory;
|
||||
import com.gmail.nossr50.core.util.ItemUtils;
|
||||
import com.gmail.nossr50.core.util.skills.SkillUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SalvageConfig extends ConfigCollections {
|
||||
private List<Salvageable> salvageables;
|
||||
|
||||
public SalvageConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), fileName, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection getLoadedCollection() {
|
||||
return salvageables == null ? new ArrayList<Salvageable>() : salvageables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
salvageables = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
salvageables = new ArrayList<Salvageable>();
|
||||
|
||||
ConfigurationSection section = config.getConfigurationSection("Salvageables");
|
||||
Set<String> keys = section.getKeys(false);
|
||||
|
||||
for (String key : keys) {
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
// ItemStack Material
|
||||
Material itemMaterial = Material.matchMaterial(key);
|
||||
|
||||
if (itemMaterial == null) {
|
||||
reason.add("Invalid material: " + key);
|
||||
}
|
||||
|
||||
// Salvage Material Type
|
||||
MaterialType salvageMaterialType = MaterialType.OTHER;
|
||||
String salvageMaterialTypeString = getStringValue("Salvageables." + key + ".MaterialType", "OTHER");
|
||||
|
||||
if (!config.contains("Salvageables." + key + ".MaterialType") && itemMaterial != null) {
|
||||
ItemStack salvageItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isWoodTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.WOOD;
|
||||
} else if (ItemUtils.isStoneTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.STONE;
|
||||
} else if (ItemUtils.isStringTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.STRING;
|
||||
} else if (ItemUtils.isLeatherArmor(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.LEATHER;
|
||||
} else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.IRON;
|
||||
} else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.GOLD;
|
||||
} else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(salvageItem)) {
|
||||
salvageMaterialType = MaterialType.DIAMOND;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
salvageMaterialType = MaterialType.valueOf(salvageMaterialTypeString.replace(" ", "_").toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid MaterialType of " + salvageMaterialTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
// Salvage Material
|
||||
String salvageMaterialName = getStringValue("Salvageables." + key + ".SalvageMaterial");
|
||||
Material salvageMaterial = (salvageMaterialName == null ? salvageMaterialType.getDefaultMaterial() : Material.matchMaterial(salvageMaterialName));
|
||||
|
||||
if (salvageMaterial == null) {
|
||||
reason.add(key + " has an invalid salvage material: " + salvageMaterialName);
|
||||
}
|
||||
|
||||
// Maximum Durability
|
||||
short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) getIntValue("Salvageables." + key + ".MaximumDurability"));
|
||||
|
||||
// ItemStack Type
|
||||
ItemType salvageItemType = ItemType.OTHER;
|
||||
String salvageItemTypeString = getStringValue("Salvageables." + key + ".ItemType", "OTHER");
|
||||
|
||||
if (!config.contains("Salvageables." + key + ".ItemType") && itemMaterial != null) {
|
||||
ItemStack salvageItem = new ItemStack(itemMaterial);
|
||||
|
||||
if (ItemUtils.isMinecraftTool(salvageItem)) {
|
||||
salvageItemType = ItemType.TOOL;
|
||||
} else if (ItemUtils.isArmor(salvageItem)) {
|
||||
salvageItemType = ItemType.ARMOR;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
salvageItemType = ItemType.valueOf(salvageItemTypeString.replace(" ", "_").toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add(key + " has an invalid ItemType of " + salvageItemTypeString);
|
||||
}
|
||||
}
|
||||
|
||||
byte salvageMetadata = (byte) getIntValue("Salvageables." + key + ".SalvageMaterialMetadata", -1);
|
||||
int minimumLevel = getIntValue("Salvageables." + key + ".MinimumLevel");
|
||||
double xpMultiplier = getDoubleValue("Salvageables." + key + ".XpMultiplier", 1);
|
||||
|
||||
if (minimumLevel < 0) {
|
||||
reason.add(key + " has an invalid MinimumLevel of " + minimumLevel);
|
||||
}
|
||||
|
||||
// Maximum Quantity
|
||||
int maximumQuantity = (itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(new ItemStack(itemMaterial), salvageMaterial, salvageMetadata) : getIntValue("Salvageables." + key + ".MaximumQuantity", 2));
|
||||
|
||||
if (maximumQuantity <= 0 && itemMaterial != null) {
|
||||
maximumQuantity = getIntValue("Salvageables." + key + ".MaximumQuantity", 1);
|
||||
}
|
||||
|
||||
int configMaximumQuantity = getIntValue("Salvageables." + key + ".MaximumQuantity", -1);
|
||||
|
||||
if (configMaximumQuantity > 0) {
|
||||
maximumQuantity = configMaximumQuantity;
|
||||
}
|
||||
|
||||
if (maximumQuantity <= 0) {
|
||||
reason.add("Maximum quantity of " + key + " must be greater than 0!");
|
||||
}
|
||||
|
||||
if (noErrorsInSalvageable(reason)) {
|
||||
Salvageable salvageable = SalvageableFactory.getSalvageable(itemMaterial, salvageMaterial, salvageMetadata, minimumLevel, maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType, xpMultiplier);
|
||||
salvageables.add(salvageable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean noErrorsInSalvageable(List<String> issues) {
|
||||
if (!issues.isEmpty()) {
|
||||
plugin.getLogger().warning("Errors have been found in: " + fileName);
|
||||
plugin.getLogger().warning("The following issues were found:");
|
||||
}
|
||||
|
||||
for (String issue : issues) {
|
||||
plugin.getLogger().warning(issue);
|
||||
}
|
||||
|
||||
return issues.isEmpty();
|
||||
}
|
||||
}
|
@ -0,0 +1,448 @@
|
||||
package com.gmail.nossr50.core.config.experience;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.ConfigValidated;
|
||||
import com.gmail.nossr50.core.datatypes.experience.FormulaType;
|
||||
import com.gmail.nossr50.core.mcmmo.BlockType;
|
||||
import com.gmail.nossr50.core.mcmmo.bossbars.BarColor;
|
||||
import com.gmail.nossr50.core.mcmmo.bossbars.BarStyle;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.EntityType;
|
||||
import com.gmail.nossr50.core.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.skills.PotionStage;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ExperienceConfig extends ConfigValidated {
|
||||
public static final String EXPLOIT_FIX = "ExploitFix";
|
||||
public static final String ENDERMAN_ENDERMITE_FARMS = "EndermanEndermiteFarms";
|
||||
public static final String EXPERIENCE = "Experience";
|
||||
public static final String EXPERIENCE_FORMULA = EXPERIENCE + "_Formula";
|
||||
public static final String CURVE = "Curve";
|
||||
public static final String VALUES = "_Values";
|
||||
public static final String MULTIPLIER = "multiplier";
|
||||
public static final String BASE = "base";
|
||||
public static final String EXPONENT = "exponent";
|
||||
public static final String MULTIPLIER1 = "Multiplier";
|
||||
public static final String GLOBAL = "Global";
|
||||
public static final String MOBSPAWNERS = "Mobspawners";
|
||||
public static final String BREEDING = "Breeding";
|
||||
public static final String MODIFIER = "Modifier";
|
||||
public static final String CUSTOM_XP_PERK = "Custom_XP_Perk";
|
||||
public static final String BOOST = "Boost";
|
||||
public static final String DIMISHED_RETURNS = "Dimished_Returns";
|
||||
public static final String GUARANTEED_MINIMUM_PERCENTAGE = "Guaranteed_Minimum_Percentage";
|
||||
public static final String DIMINISHED_RETURNS = "Diminished_Returns";
|
||||
public static final String ENABLE = "Enable";
|
||||
public static final String ENABLED = ENABLE + "d";
|
||||
public static final String TIME_INTERVAL = "Time_Interval";
|
||||
public static final String CONVERSION = "Conversion";
|
||||
public static final String EXP = "Exp_";
|
||||
public static final String PVP = "PVP";
|
||||
public static final String REWARDS = "Rewards";
|
||||
public static final String COMBAT = "Combat";
|
||||
public static final String ANIMALS = "Animals";
|
||||
public static final String BARS = "_Bars";
|
||||
public static final String UPDATE = "Update";
|
||||
public static final String PASSIVE = "Passive";
|
||||
public static final String THIS_MAY_CAUSE_LAG = "ThisMayCauseLag";
|
||||
public static final String ALWAYS = "Always";
|
||||
public static final String TITLES_WHEN_XPIS_GAINED = "TitlesWhenXPIsGained";
|
||||
public static final String EXTRA_DETAILS = "ExtraDetails";
|
||||
public static final String COLOR = "Color";
|
||||
public static final String BAR_STYLE = "BarStyle";
|
||||
public static final String ACROBATICS = "Acrobatics";
|
||||
public static final String DODGE = "Dodge";
|
||||
public static final String ROLL = "Roll";
|
||||
public static final String FALL = "Fall";
|
||||
public static final String FEATHER = "Feather";
|
||||
public static final String ALCHEMY = "Alchemy";
|
||||
public static final String POTION_STAGE = "Potion_Stage_";
|
||||
public static final String ARCHERY = "Archery";
|
||||
public static final String DISTANCE = "Distance_";
|
||||
public static final String FISHING = "Fishing";
|
||||
public static final String SHAKE = "Shake";
|
||||
public static final String REPAIR = "Repair";
|
||||
public static final String BASE1 = "Base";
|
||||
public static final String TAMING = "Taming";
|
||||
public static final String ANIMAL_TAMING = "Animal_Taming";
|
||||
public static final String PARTY = "Party";
|
||||
public static final String THRESHOLD = "Threshold";
|
||||
public static final String CUMULATIVE = "Cumulative_";
|
||||
public static final String OCELOT = "Ocelot";
|
||||
public static final String WOLF = "Wolf";
|
||||
public static final String FEATHER_FALL_MULTIPLIER = "FeatherFall_Multiplier";
|
||||
private static ExperienceConfig instance;
|
||||
|
||||
//TODO: Should merge be false? Seems okay to leave it as true..
|
||||
private ExperienceConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), "experience.yml", true);
|
||||
}
|
||||
|
||||
public static ExperienceConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ExperienceConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
instance = null; //TODO: this might be a bit problematic
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateKeys() {
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
/*
|
||||
* FORMULA SETTINGS
|
||||
*/
|
||||
|
||||
/* Curve values */
|
||||
if (getMultiplier(FormulaType.EXPONENTIAL) <= 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + ".Exponential" + VALUES + "." + MULTIPLIER + " should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getMultiplier(FormulaType.LINEAR) <= 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + ".Linear" + VALUES + "." + MULTIPLIER + " should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getExponent(FormulaType.EXPONENTIAL) <= 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + ".Exponential" + VALUES + "." + EXPONENT + " should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Global modifier */
|
||||
if (getExperienceGainsGlobalMultiplier() <= 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + "." + MULTIPLIER1 + "." + GLOBAL + " should be greater than 0!");
|
||||
}
|
||||
|
||||
/* PVP modifier */
|
||||
if (getPlayerVersusPlayerXP() < 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + "." + MULTIPLIER1 + "." + PVP + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* Spawned Mob modifier */
|
||||
if (getSpawnedMobXpMultiplier() < 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + "." + MOBSPAWNERS + "." + MULTIPLIER1 + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* Bred Mob modifier */
|
||||
if (getBredMobXpMultiplier() < 0) {
|
||||
reason.add(EXPERIENCE_FORMULA + "." + BREEDING + "." + MULTIPLIER1 + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* Conversion */
|
||||
if (getExpModifier() <= 0) {
|
||||
reason.add(CONVERSION + "." + EXP + MODIFIER + " should be greater than 0!");
|
||||
}
|
||||
|
||||
/*
|
||||
* XP SETTINGS
|
||||
*/
|
||||
|
||||
/* Alchemy */
|
||||
for (PotionStage potionStage : PotionStage.values()) {
|
||||
if (getPotionXP(potionStage) < 0) {
|
||||
reason.add(EXPERIENCE + "." + ALCHEMY + "." + POTION_STAGE + potionStage.toNumerical() + " should be at least 0!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Archery */
|
||||
if (getArcheryDistanceMultiplier() < 0) {
|
||||
reason.add(EXPERIENCE + "." + ARCHERY + "." + DISTANCE + MULTIPLIER1 + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* Combat XP Multipliers */
|
||||
if (getAnimalsXP() < 0) {
|
||||
reason.add(EXPERIENCE + "." + COMBAT + "." + MULTIPLIER1 + "." + ANIMALS + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getDodgeXPModifier() < 0) {
|
||||
reason.add("Skills." + ACROBATICS + "." + DODGE + "_XP_" + MODIFIER + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getRollXPModifier() < 0) {
|
||||
reason.add("Skills." + ACROBATICS + "." + ROLL + "_XP_" + MODIFIER + " should be at least 0!");
|
||||
}
|
||||
|
||||
if (getFallXPModifier() < 0) {
|
||||
reason.add("Skills." + ACROBATICS + "." + FALL + "_XP_" + MODIFIER + " should be at least 0!");
|
||||
}
|
||||
|
||||
/* Fishing */
|
||||
// TODO: Add validation for each fish type once enum is available.
|
||||
|
||||
if (getFishingShakeXP() <= 0) {
|
||||
reason.add(EXPERIENCE + "." + FISHING + "." + SHAKE + " should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Repair */
|
||||
if (getRepairXPBase() <= 0) {
|
||||
reason.add(EXPERIENCE + "." + REPAIR + "." + BASE1 + " should be greater than 0!");
|
||||
}
|
||||
|
||||
/* Taming */
|
||||
if (getTamingXP(EntityType.WOLF) <= 0) {
|
||||
reason.add(EXPERIENCE + "." + TAMING + "." + ANIMAL_TAMING + "." + WOLF + " should be greater than 0!");
|
||||
}
|
||||
|
||||
if (getTamingXP(EntityType.OCELOT) <= 0) {
|
||||
reason.add(EXPERIENCE + "." + TAMING + "." + ANIMAL_TAMING + "." + OCELOT + " should be greater than 0!");
|
||||
}
|
||||
|
||||
return reason;
|
||||
}
|
||||
|
||||
/*
|
||||
* FORMULA SETTINGS
|
||||
*/
|
||||
|
||||
/* EXPLOIT TOGGLES */
|
||||
public boolean isEndermanEndermiteFarmingPrevented() {
|
||||
return getBooleanValue(EXPLOIT_FIX, ENDERMAN_ENDERMITE_FARMS);
|
||||
}
|
||||
|
||||
/* Curve settings */
|
||||
public FormulaType getFormulaType() {
|
||||
return FormulaType.getFormulaType(getStringValue(EXPERIENCE_FORMULA, CURVE));
|
||||
}
|
||||
|
||||
public boolean getCumulativeCurveEnabled() {
|
||||
return getBooleanValue(EXPERIENCE_FORMULA, CUMULATIVE + CURVE);
|
||||
}
|
||||
|
||||
/* Curve values */
|
||||
public double getMultiplier(FormulaType type) {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, StringUtils.getCapitalized(type.toString()) + VALUES, MULTIPLIER);
|
||||
}
|
||||
|
||||
public int getBase(FormulaType type) {
|
||||
return getIntValue(EXPERIENCE_FORMULA, StringUtils.getCapitalized(type.toString()) + VALUES, BASE);
|
||||
}
|
||||
|
||||
public double getExponent(FormulaType type) {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, StringUtils.getCapitalized(type.toString()) + VALUES, EXPONENT);
|
||||
}
|
||||
|
||||
/* Global modifier */
|
||||
public double getExperienceGainsGlobalMultiplier() {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, MULTIPLIER1, GLOBAL);
|
||||
}
|
||||
|
||||
//TODO: Rewrite this
|
||||
/*public void setExperienceGainsGlobalMultiplier(double value) {
|
||||
config.set(EXPERIENCE_FORMULA, MULTIPLIER1, GLOBAL, value);
|
||||
}*/
|
||||
|
||||
/* PVP modifier */
|
||||
public double getPlayerVersusPlayerXP() {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, MULTIPLIER1, PVP);
|
||||
}
|
||||
|
||||
/* Spawned Mob modifier */
|
||||
public double getSpawnedMobXpMultiplier() {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, MOBSPAWNERS, MULTIPLIER1);
|
||||
}
|
||||
|
||||
public double getBredMobXpMultiplier() {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, BREEDING, MULTIPLIER1);
|
||||
}
|
||||
|
||||
/* Skill modifiers */
|
||||
public double getFormulaSkillModifier(PrimarySkillType skill) {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, MODIFIER, StringUtils.getCapitalized(skill.toString()));
|
||||
}
|
||||
|
||||
/* Custom XP perk */
|
||||
public double getCustomXpPerkBoost() {
|
||||
return getDoubleValue(EXPERIENCE_FORMULA, CUSTOM_XP_PERK, BOOST);
|
||||
}
|
||||
|
||||
/* Diminished Returns */
|
||||
public float getDiminishedReturnsCap() {
|
||||
return (float) getDoubleValue(DIMISHED_RETURNS, GUARANTEED_MINIMUM_PERCENTAGE);
|
||||
}
|
||||
|
||||
public boolean getDiminishedReturnsEnabled() {
|
||||
return getBooleanValue(DIMINISHED_RETURNS, ENABLED);
|
||||
}
|
||||
|
||||
public int getDiminishedReturnsThreshold(PrimarySkillType skill) {
|
||||
return getIntValue(DIMINISHED_RETURNS, THRESHOLD, StringUtils.getCapitalized(skill.toString()));
|
||||
}
|
||||
|
||||
public int getDiminishedReturnsTimeInterval() {
|
||||
return getIntValue(DIMINISHED_RETURNS, TIME_INTERVAL);
|
||||
}
|
||||
|
||||
/* Conversion */
|
||||
public double getExpModifier() {
|
||||
return getDoubleValue(CONVERSION, EXP + MODIFIER);
|
||||
}
|
||||
|
||||
/*
|
||||
* XP SETTINGS
|
||||
*/
|
||||
|
||||
/* General Settings */
|
||||
public boolean getExperienceGainsPlayerVersusPlayerEnabled() {
|
||||
return getBooleanValue(EXPERIENCE, PVP, REWARDS);
|
||||
}
|
||||
|
||||
/* Combat XP Multipliers */
|
||||
public double getCombatXP(EntityType entity) {
|
||||
return getDoubleValue(EXPERIENCE, COMBAT, MULTIPLIER1, entity.getConfigName());
|
||||
}
|
||||
|
||||
public double getAnimalsXP(EntityType entity) {
|
||||
return getDoubleValue(EXPERIENCE, COMBAT, MULTIPLIER1, entity.getConfigName());
|
||||
}
|
||||
|
||||
public double getAnimalsXP() {
|
||||
return getDoubleValue(EXPERIENCE, COMBAT, MULTIPLIER1, ANIMALS);
|
||||
}
|
||||
|
||||
public boolean hasCombatXP(EntityType entity) {
|
||||
return hasNode(EXPERIENCE, COMBAT, MULTIPLIER1, entity.getConfigName());
|
||||
}
|
||||
|
||||
/* Materials */
|
||||
|
||||
/**
|
||||
* Gets the raw XP given for breaking this block, this does not include modifiers
|
||||
* @param skill The skill to give XP for
|
||||
* @param blockType the type of block
|
||||
* @return the raw amount of XP for this block before modifiers
|
||||
*/
|
||||
public int getXp(PrimarySkillType skill, BlockType blockType) {
|
||||
//TODO: This is going to need to be changed, this code here is only placeholder
|
||||
String[] path = new String[]{ EXPERIENCE, StringUtils.getCapitalized(skill.toString()), blockType.getConfigName() };
|
||||
return getIntValue(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block gives XP
|
||||
* This is used to determine whether or not mcMMO should track a block that is placed by a user, among other things.
|
||||
* Note: If the block has an entry in the config that will return true even if the XP is 0, this does not check the value of the XP
|
||||
* @param skill The skill to check for
|
||||
* @param blockType the type of block
|
||||
* @return true if the block does give XP
|
||||
*/
|
||||
public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockType blockType) {
|
||||
//TODO: This used to support wildcard characters, seems a bit unnecessary to do so.
|
||||
//TODO: This is going to need to be changed, this code here is only placeholder
|
||||
String[] path = new String[] {EXPERIENCE, StringUtils.getCapitalized(skill.toString()), blockType.getConfigName()};
|
||||
return hasNode(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Experience Bar Stuff
|
||||
*/
|
||||
|
||||
public boolean isPartyExperienceBarsEnabled() {
|
||||
return getBooleanValue(EXPERIENCE + BARS, UPDATE, PARTY);
|
||||
}
|
||||
|
||||
public boolean isPassiveGainsExperienceBarsEnabled() {
|
||||
return getBooleanValue(EXPERIENCE + BARS, UPDATE, PASSIVE);
|
||||
}
|
||||
|
||||
public boolean getDoExperienceBarsAlwaysUpdateTitle() {
|
||||
return getBooleanValue(EXPERIENCE + BARS, THIS_MAY_CAUSE_LAG, ALWAYS + UPDATE + TITLES_WHEN_XPIS_GAINED, ENABLE) || getAddExtraDetails();
|
||||
}
|
||||
|
||||
public boolean getAddExtraDetails() {
|
||||
return getBooleanValue(EXPERIENCE + BARS, THIS_MAY_CAUSE_LAG, ALWAYS + UPDATE + TITLES_WHEN_XPIS_GAINED, EXTRA_DETAILS);
|
||||
}
|
||||
|
||||
public boolean isExperienceBarsEnabled() {
|
||||
return getBooleanValue(EXPERIENCE + BARS, ENABLE);
|
||||
}
|
||||
|
||||
public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) {
|
||||
return getBooleanValue(EXPERIENCE + BARS, StringUtils.getCapitalized(primarySkillType.toString()), ENABLE);
|
||||
}
|
||||
|
||||
public BarColor getExperienceBarColor(PrimarySkillType primarySkillType) {
|
||||
String colorValueFromConfig = getStringValue(EXPERIENCE + BARS, StringUtils.getCapitalized(primarySkillType.toString()), COLOR);
|
||||
|
||||
for (BarColor barColor : BarColor.values()) {
|
||||
if (barColor.toString().equalsIgnoreCase(colorValueFromConfig))
|
||||
return barColor;
|
||||
}
|
||||
|
||||
//In case the value is invalid
|
||||
return BarColor.WHITE;
|
||||
}
|
||||
|
||||
public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType) {
|
||||
String colorValueFromConfig = getStringValue(EXPERIENCE + BARS, StringUtils.getCapitalized(primarySkillType.toString()), BAR_STYLE);
|
||||
|
||||
for (BarStyle barStyle : BarStyle.values()) {
|
||||
if (barStyle.toString().equalsIgnoreCase(colorValueFromConfig))
|
||||
return barStyle;
|
||||
}
|
||||
|
||||
//In case the value is invalid
|
||||
return BarStyle.SOLID;
|
||||
}
|
||||
|
||||
/* Acrobatics */
|
||||
public int getDodgeXPModifier() {
|
||||
return getIntValue(EXPERIENCE, ACROBATICS, DODGE);
|
||||
}
|
||||
|
||||
public int getRollXPModifier() {
|
||||
return getIntValue(EXPERIENCE, ACROBATICS, ROLL);
|
||||
}
|
||||
|
||||
public int getFallXPModifier() {
|
||||
return getIntValue(EXPERIENCE, ACROBATICS, FALL);
|
||||
}
|
||||
|
||||
public double getFeatherFallXPModifier() {
|
||||
return getDoubleValue(EXPERIENCE, ACROBATICS, FEATHER_FALL_MULTIPLIER);
|
||||
}
|
||||
|
||||
/* Alchemy */
|
||||
public double getPotionXP(PotionStage stage) {
|
||||
return getDoubleValue(EXPERIENCE, ALCHEMY, POTION_STAGE + stage.toNumerical());
|
||||
}
|
||||
|
||||
/* Archery */
|
||||
public double getArcheryDistanceMultiplier() {
|
||||
return getDoubleValue(EXPERIENCE, ARCHERY, DISTANCE + MULTIPLIER1);
|
||||
}
|
||||
|
||||
public int getFishingShakeXP() {
|
||||
return getIntValue(EXPERIENCE, FISHING, SHAKE);
|
||||
}
|
||||
|
||||
/* Repair */
|
||||
public double getRepairXPBase() {
|
||||
return getDoubleValue(EXPERIENCE, REPAIR, BASE1);
|
||||
}
|
||||
|
||||
public double getRepairXP(MaterialType repairMaterialType) {
|
||||
return getDoubleValue(EXPERIENCE, REPAIR, StringUtils.getCapitalized(repairMaterialType.toString()));
|
||||
}
|
||||
|
||||
/* Taming */
|
||||
public int getTamingXP(EntityType type) {
|
||||
return getIntValue(EXPERIENCE, TAMING, ANIMAL_TAMING, type.getConfigName());
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArmorConfigManager {
|
||||
public ArmorConfigManager() {
|
||||
Pattern middlePattern = Pattern.compile("armor\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.armor\\.yml");
|
||||
File dataFolder = new File(McmmoCore.getModDataFolderPath());
|
||||
File vanilla = new File(dataFolder, "armor.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "armor.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomArmor(new CustomArmorConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BlockConfigManager {
|
||||
public BlockConfigManager() {
|
||||
Pattern middlePattern = Pattern.compile("blocks\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.blocks\\.yml");
|
||||
File dataFolder = new File(McmmoCore.getModDataFolderPath());
|
||||
File vanilla = new File(dataFolder, "blocks.default.yml");
|
||||
ModManager modManager = McmmoCore.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "blocks.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomBlocks(new CustomBlockConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.ConfigCollections;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.ConfigItemCategory;
|
||||
import com.gmail.nossr50.core.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.core.util.skills.SkillUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomArmorConfig extends ConfigCollections {
|
||||
public List<Material> customBoots = new ArrayList<Material>();
|
||||
public List<Material> customChestplates = new ArrayList<Material>();
|
||||
public List<Material> customHelmets = new ArrayList<Material>();
|
||||
public List<Material> customLeggings = new ArrayList<Material>();
|
||||
public List<Repairable> repairables = new ArrayList<Repairable>();
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
protected CustomArmorConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getPath() + "mods", fileName, false);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this config
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public double getConfigVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadKeys() {
|
||||
loadArmor("Boots", customBoots);
|
||||
loadArmor("Chestplates", customChestplates);
|
||||
loadArmor("Helmets", customHelmets);
|
||||
loadArmor("Leggings", customLeggings);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadArmor(String armorType, List<Material> materialList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection armorSection = config.getConfigurationSection(armorType);
|
||||
|
||||
if (armorSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> armorConfigSet = armorSection.getKeys(false);
|
||||
|
||||
for (String armorName : armorConfigSet) {
|
||||
if (config.contains(armorType + "." + armorName + "." + ".ID")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Material armorMaterial = Material.matchMaterial(armorName);
|
||||
|
||||
if (armorMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean repairable = getBooleanValue(armorType + "." + armorName + ".Repairable");
|
||||
Material repairMaterial = Material.matchMaterial(getStringValue(armorType + "." + armorName + ".Repair_Material", ""));
|
||||
|
||||
if (repairable && (repairMaterial == null)) {
|
||||
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName);
|
||||
repairable = false;
|
||||
}
|
||||
|
||||
if (repairable) {
|
||||
byte repairData = (byte) getIntValue(armorType + "." + armorName + ".Repair_Material_Data_Value", -1);
|
||||
int repairQuantity = SkillUtils.getRepairAndSalvageQuantities(new ItemStack(armorMaterial), repairMaterial, repairData);
|
||||
|
||||
if (repairQuantity == 0) {
|
||||
repairQuantity = getIntValue(armorType + "." + armorName + ".Repair_Material_Quantity", 2);
|
||||
}
|
||||
|
||||
String repairItemName = getStringValue(armorType + "." + armorName + ".Repair_Material_Pretty_Name");
|
||||
int repairMinimumLevel = getIntValue(armorType + "." + armorName + ".Repair_MinimumLevel", 0);
|
||||
double repairXpMultiplier = getDoubleValue(armorType + "." + armorName + ".Repair_XpMultiplier", 1);
|
||||
|
||||
short durability = armorMaterial.getMaxDurability();
|
||||
|
||||
if (durability == 0) {
|
||||
durability = (short) getIntValue(armorType + "." + armorName + ".Durability", 70);
|
||||
}
|
||||
|
||||
repairables.add(RepairableFactory.getRepairable(armorMaterial, repairMaterial, repairData, repairItemName, repairMinimumLevel, repairQuantity, durability, ConfigItemCategory.ARMOR, MaterialType.OTHER, repairXpMultiplier));
|
||||
}
|
||||
|
||||
materialList.add(armorMaterial);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.ConfigCollections;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomBlock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomBlockConfig extends ConfigCollections {
|
||||
public List<Material> customExcavationBlocks = new ArrayList<>();
|
||||
public List<Material> customHerbalismBlocks = new ArrayList<>();
|
||||
public List<Material> customMiningBlocks = new ArrayList<>();
|
||||
public List<Material> customOres = new ArrayList<>();
|
||||
public List<Material> customLogs = new ArrayList<>();
|
||||
public List<Material> customLeaves = new ArrayList<>();
|
||||
public List<Material> customAbilityBlocks = new ArrayList<>();
|
||||
public HashMap<Material, CustomBlock> customBlockMap = new HashMap<>();
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
protected CustomBlockConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getPath() + "mods", fileName, false);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadBlocks("Excavation", customExcavationBlocks);
|
||||
loadBlocks("Herbalism", customHerbalismBlocks);
|
||||
loadBlocks("Mining", customMiningBlocks);
|
||||
loadBlocks("Woodcutting", null);
|
||||
loadBlocks("Ability_Blocks", customAbilityBlocks);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadBlocks(String skillType, List<Material> blockList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection skillSection = config.getConfigurationSection(skillType);
|
||||
|
||||
if (skillSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> skillConfigSet = skillSection.getKeys(false);
|
||||
|
||||
for (String blockName : skillConfigSet) {
|
||||
if (config.contains(skillType + "." + blockName + ".Drop_Item")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
String[] blockInfo = blockName.split("[|]");
|
||||
|
||||
Material blockMaterial = Material.matchMaterial(blockInfo[0]);
|
||||
|
||||
if (blockMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockList != null) {
|
||||
blockList.add(blockMaterial);
|
||||
}
|
||||
|
||||
if (skillType.equals("Ability_Blocks")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int xp = getIntValue(skillType + "." + blockName + ".XP_Gain");
|
||||
int smeltingXp = 0;
|
||||
|
||||
if (skillType.equals("Mining") && getBooleanValue(skillType + "." + blockName + ".Is_Ore")) {
|
||||
customOres.add(blockMaterial);
|
||||
smeltingXp = getIntValue(skillType + "." + blockName + ".Smelting_XP_Gain", xp / 10);
|
||||
} else if (skillType.equals("Woodcutting")) {
|
||||
if (getBooleanValue(skillType + "." + blockName + ".Is_Log")) {
|
||||
customLogs.add(blockMaterial);
|
||||
} else {
|
||||
customLeaves.add(blockMaterial);
|
||||
xp = 0; // Leaves don't grant XP
|
||||
}
|
||||
}
|
||||
|
||||
customBlockMap.put(blockMaterial, new CustomBlock(xp, getBooleanValue(skillType + "." + blockName + ".Double_Drops_Enabled"), smeltingXp));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomEntity;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CustomEntityConfig extends Config {
|
||||
public HashMap<String, CustomEntity> customEntityClassMap = new HashMap<String, CustomEntity>();
|
||||
public HashMap<String, CustomEntity> customEntityTypeMap = new HashMap<String, CustomEntity>();
|
||||
|
||||
protected CustomEntityConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getPath() + "mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
if (config.getConfigurationSection("Hostile") != null) {
|
||||
backup();
|
||||
return;
|
||||
}
|
||||
|
||||
for (String entityName : config.getKeys(false)) {
|
||||
Class<?> clazz = null;
|
||||
String className = getStringValue(entityName + ".Class", "");
|
||||
|
||||
try {
|
||||
clazz = ClassUtils.getClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + ".");
|
||||
plugin.getLogger().warning("This custom entity may not function properly.");
|
||||
}
|
||||
|
||||
String entityTypeName = entityName.replace("_", ".");
|
||||
double xpMultiplier = getDoubleValue(entityName + ".XP_Multiplier", 1.0D);
|
||||
|
||||
boolean canBeTamed = getBooleanValue(entityName + ".Tameable");
|
||||
int tamingXp = getIntValue(entityName + ".Taming_XP");
|
||||
|
||||
boolean canBeSummoned = getBooleanValue(entityName + ".CanBeSummoned");
|
||||
Material callOfTheWildMaterial = Material.matchMaterial(getStringValue(entityName + ".COTW_Material", ""));
|
||||
byte callOfTheWildData = (byte) getIntValue(entityName + ".COTW_Material_Data");
|
||||
int callOfTheWildAmount = getIntValue(entityName + ".COTW_Material_Amount");
|
||||
|
||||
if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) {
|
||||
plugin.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild.");
|
||||
canBeSummoned = false;
|
||||
}
|
||||
|
||||
CustomEntity entity = new CustomEntity(xpMultiplier, canBeTamed, tamingXp, canBeSummoned, (canBeSummoned ? new ItemStack(callOfTheWildMaterial) : null), callOfTheWildAmount);
|
||||
|
||||
customEntityTypeMap.put(entityTypeName, entity);
|
||||
customEntityClassMap.put(clazz == null ? null : clazz.getName(), entity);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomTool;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.MaterialType;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.Repairable;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.repairables.RepairableFactory;
|
||||
import com.gmail.nossr50.core.util.skills.SkillUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class CustomToolConfig extends Config {
|
||||
public List<Material> customAxes = new ArrayList<Material>();
|
||||
public List<Material> customBows = new ArrayList<Material>();
|
||||
public List<Material> customHoes = new ArrayList<Material>();
|
||||
public List<Material> customPickaxes = new ArrayList<Material>();
|
||||
public List<Material> customShovels = new ArrayList<Material>();
|
||||
public List<Material> customSwords = new ArrayList<Material>();
|
||||
public HashMap<Material, CustomTool> customToolMap = new HashMap<Material, CustomTool>();
|
||||
public List<Repairable> repairables = new ArrayList<Repairable>();
|
||||
private boolean needsUpdate = false;
|
||||
|
||||
protected CustomToolConfig(String fileName) {
|
||||
super(McmmoCore.getDataFolderPath().getPath() + "mods", fileName);
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadTool("Axes", customAxes);
|
||||
loadTool("Bows", customBows);
|
||||
loadTool("Hoes", customHoes);
|
||||
loadTool("Pickaxes", customPickaxes);
|
||||
loadTool("Shovels", customShovels);
|
||||
loadTool("Swords", customSwords);
|
||||
|
||||
if (needsUpdate) {
|
||||
needsUpdate = false;
|
||||
backup();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTool(String toolType, List<Material> materialList) {
|
||||
if (needsUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigurationSection toolSection = config.getConfigurationSection(toolType);
|
||||
|
||||
if (toolSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> toolConfigSet = toolSection.getKeys(false);
|
||||
|
||||
for (String toolName : toolConfigSet) {
|
||||
if (config.contains(toolType + "." + toolName + "." + ".ID")) {
|
||||
needsUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Material toolMaterial = Material.matchMaterial(toolName);
|
||||
|
||||
if (toolMaterial == null) {
|
||||
plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean repairable = getBooleanValue(toolType + "." + toolName + ".Repairable");
|
||||
Material repairMaterial = Material.matchMaterial(getStringValue(toolType + "." + toolName + ".Repair_Material", ""));
|
||||
|
||||
if (repairable && (repairMaterial == null)) {
|
||||
plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName);
|
||||
repairable = false;
|
||||
}
|
||||
|
||||
if (repairable) {
|
||||
byte repairData = (byte) getIntValue(toolType + "." + toolName + ".Repair_Material_Data_Value", -1);
|
||||
int repairQuantity = SkillUtils.getRepairAndSalvageQuantities(new ItemStack(toolMaterial), repairMaterial, repairData);
|
||||
|
||||
if (repairQuantity == 0) {
|
||||
repairQuantity = getIntValue(toolType + "." + toolName + ".Repair_Material_Quantity", 2);
|
||||
}
|
||||
|
||||
String repairItemName = getStringValue(toolType + "." + toolName + ".Repair_Material_Pretty_Name");
|
||||
int repairMinimumLevel = getIntValue(toolType + "." + toolName + ".Repair_MinimumLevel", 0);
|
||||
double repairXpMultiplier = getDoubleValue(toolType + "." + toolName + ".Repair_XpMultiplier", 1);
|
||||
|
||||
short durability = toolMaterial.getMaxDurability();
|
||||
|
||||
if (durability == 0) {
|
||||
durability = (short) getIntValue(toolType + "." + toolName + ".Durability", 60);
|
||||
}
|
||||
|
||||
repairables.add(RepairableFactory.getRepairable(toolMaterial, repairMaterial, repairData, repairItemName, repairMinimumLevel, repairQuantity, durability, ItemType.TOOL, MaterialType.OTHER, repairXpMultiplier));
|
||||
}
|
||||
|
||||
double multiplier = getDoubleValue(toolType + "." + toolName + ".XP_Modifier", 1.0);
|
||||
boolean abilityEnabled = getBooleanValue(toolType + "." + toolName + ".Ability_Enabled", true);
|
||||
int tier = getIntValue(toolType + "." + toolName + ".Tier", 1);
|
||||
|
||||
CustomTool tool = new CustomTool(tier, abilityEnabled, multiplier);
|
||||
|
||||
materialList.add(toolMaterial);
|
||||
customToolMap.put(toolMaterial, tool);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
|
||||
import com.gmail.nossr50.core.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class EntityConfigManager {
|
||||
public EntityConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("entities\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.entities\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "entities.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "entities.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomEntities(new CustomEntityConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.gmail.nossr50.core.config.mods;
|
||||
|
||||
|
||||
import com.gmail.nossr50.core.util.ModManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ToolConfigManager {
|
||||
public ToolConfigManager(mcMMO plugin) {
|
||||
Pattern middlePattern = Pattern.compile("tools\\.(?:.+)\\.yml");
|
||||
Pattern startPattern = Pattern.compile("(?:.+)\\.tools\\.yml");
|
||||
File dataFolder = new File(mcMMO.getModDirectory());
|
||||
File vanilla = new File(dataFolder, "tools.default.yml");
|
||||
ModManager modManager = mcMMO.getModManager();
|
||||
|
||||
if (!vanilla.exists()) {
|
||||
plugin.saveResource(vanilla.getParentFile().getName() + File.separator + "tools.default.yml", false);
|
||||
}
|
||||
|
||||
for (String fileName : dataFolder.list()) {
|
||||
if (!middlePattern.matcher(fileName).matches() && !startPattern.matcher(fileName).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File file = new File(dataFolder, fileName);
|
||||
|
||||
if (file.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modManager.registerCustomTools(new CustomToolConfig(fileName));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.gmail.nossr50.core.config.party;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
public class ItemWeightConfig extends Config {
|
||||
private static ItemWeightConfig instance;
|
||||
|
||||
private ItemWeightConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(), "itemweights.yml");
|
||||
}
|
||||
|
||||
public static ItemWeightConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ItemWeightConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getItemWeight(Material material) {
|
||||
return getIntValue("Item_Weights." + StringUtils.getPrettyItemString(material).replace(" ", "_"), getIntValue("Item_Weights.Default"));
|
||||
}
|
||||
|
||||
public HashSet<Material> getMiscItems() {
|
||||
HashSet<Material> miscItems = new HashSet<Material>();
|
||||
|
||||
for (String item : getStringValueList("Party_Shareables.Misc_Items")) {
|
||||
Material material = Material.getMaterial(item.toUpperCase());
|
||||
|
||||
if (material != null) {
|
||||
miscItems.add(material);
|
||||
}
|
||||
}
|
||||
return miscItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
}
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
package com.gmail.nossr50.core.config.skills.alchemy;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.mcmmo.colors.ChatColor;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.primary.alchemy.AlchemyPotion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PotionConfig extends Config {
|
||||
private static PotionConfig instance;
|
||||
|
||||
private List<ItemStack> concoctionsIngredientsTierOne = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierTwo = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierThree = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierFour = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierFive = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierSix = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<ItemStack>();
|
||||
private List<ItemStack> concoctionsIngredientsTierEight = new ArrayList<ItemStack>();
|
||||
|
||||
private Map<String, AlchemyPotion> potionMap = new HashMap<String, AlchemyPotion>();
|
||||
|
||||
private PotionConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(),"potions.yml");
|
||||
loadKeys();
|
||||
}
|
||||
|
||||
public static PotionConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new PotionConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
loadConcoctions();
|
||||
loadPotionMap();
|
||||
}
|
||||
|
||||
private void loadConcoctions() {
|
||||
ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions");
|
||||
|
||||
loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierFour, concoctionSection.getStringList("Tier_Four_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierFive, concoctionSection.getStringList("Tier_Five_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierSix, concoctionSection.getStringList("Tier_Six_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierSeven, concoctionSection.getStringList("Tier_Seven_Ingredients"));
|
||||
loadConcoctionsTier(concoctionsIngredientsTierEight, concoctionSection.getStringList("Tier_Eight_Ingredients"));
|
||||
|
||||
concoctionsIngredientsTierTwo.addAll(concoctionsIngredientsTierOne);
|
||||
concoctionsIngredientsTierThree.addAll(concoctionsIngredientsTierTwo);
|
||||
concoctionsIngredientsTierFour.addAll(concoctionsIngredientsTierThree);
|
||||
concoctionsIngredientsTierFive.addAll(concoctionsIngredientsTierFour);
|
||||
concoctionsIngredientsTierSix.addAll(concoctionsIngredientsTierFive);
|
||||
concoctionsIngredientsTierSeven.addAll(concoctionsIngredientsTierSix);
|
||||
concoctionsIngredientsTierEight.addAll(concoctionsIngredientsTierSeven);
|
||||
}
|
||||
|
||||
private void loadConcoctionsTier(List<ItemStack> ingredientList, List<String> ingredientStrings) {
|
||||
if (ingredientStrings != null && ingredientStrings.size() > 0) {
|
||||
for (String ingredientString : ingredientStrings) {
|
||||
ItemStack ingredient = loadIngredient(ingredientString);
|
||||
|
||||
if (ingredient != null) {
|
||||
ingredientList.add(ingredient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the Potions configuration section and load all defined potions.
|
||||
*/
|
||||
private void loadPotionMap() {
|
||||
ConfigurationSection potionSection = config.getConfigurationSection("Potions");
|
||||
int pass = 0;
|
||||
int fail = 0;
|
||||
|
||||
for (String potionName : potionSection.getKeys(false)) {
|
||||
AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName));
|
||||
|
||||
if (potion != null) {
|
||||
potionMap.put(potionName, potion);
|
||||
pass++;
|
||||
} else {
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
mcMMO.p.debug("Loaded " + pass + " Alchemy potions, skipped " + fail + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a ConfigurationSection representing a AlchemyPotion.
|
||||
* Returns null if input cannot be parsed.
|
||||
*
|
||||
* @param potion_section ConfigurationSection to be parsed.
|
||||
* @return Parsed AlchemyPotion.
|
||||
*/
|
||||
private AlchemyPotion loadPotion(ConfigurationSection potion_section) {
|
||||
try {
|
||||
|
||||
|
||||
String name = potion_section.getString("Name");
|
||||
if (name != null) {
|
||||
name = ChatColor.translateAlternateColorCodes('&', name);
|
||||
}
|
||||
|
||||
PotionData data;
|
||||
if (!potion_section.contains("PotionData")) { // Backwards config compatability
|
||||
short dataValue = Short.parseShort(potion_section.getName());
|
||||
Potion potion = Potion.fromDamage(dataValue);
|
||||
data = new PotionData(potion.getType(), potion.hasExtendedDuration(), potion.getLevel() == 2);
|
||||
} else {
|
||||
ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData");
|
||||
data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false));
|
||||
}
|
||||
|
||||
Material material = Material.POTION;
|
||||
String mat = potion_section.getString("Material", null);
|
||||
if (mat != null) {
|
||||
material = Material.valueOf(mat);
|
||||
}
|
||||
|
||||
List<String> lore = new ArrayList<String>();
|
||||
if (potion_section.contains("Lore")) {
|
||||
for (String line : potion_section.getStringList("Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', line));
|
||||
}
|
||||
}
|
||||
|
||||
List<PotionEffect> effects = new ArrayList<PotionEffect>();
|
||||
if (potion_section.contains("Effects")) {
|
||||
for (String effect : potion_section.getStringList("Effects")) {
|
||||
String[] parts = effect.split(" ");
|
||||
|
||||
PotionEffectType type = parts.length > 0 ? PotionEffectType.getByName(parts[0]) : null;
|
||||
int amplifier = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
|
||||
int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
|
||||
|
||||
if (type != null) {
|
||||
effects.add(new PotionEffect(type, duration, amplifier));
|
||||
} else {
|
||||
mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color color = null;
|
||||
if (potion_section.contains("Color")) {
|
||||
color = Color.fromRGB(potion_section.getInt("Color"));
|
||||
} else {
|
||||
color = this.generateColor(effects);
|
||||
}
|
||||
|
||||
Map<ItemStack, String> children = new HashMap<ItemStack, String>();
|
||||
if (potion_section.contains("Children")) {
|
||||
for (String child : potion_section.getConfigurationSection("Children").getKeys(false)) {
|
||||
ItemStack ingredient = loadIngredient(child);
|
||||
if (ingredient != null) {
|
||||
children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child));
|
||||
} else {
|
||||
mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AlchemyPotion(material, data, name, lore, effects, color, children);
|
||||
} catch (Exception e) {
|
||||
mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string representation of an ingredient.
|
||||
* Format: '<MATERIAL>[:data]'
|
||||
* Returns null if input cannot be parsed.
|
||||
*
|
||||
* @param ingredient String representing an ingredient.
|
||||
* @return Parsed ingredient.
|
||||
*/
|
||||
private ItemStack loadIngredient(String ingredient) {
|
||||
if (ingredient == null || ingredient.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Material material = Material.getMaterial(ingredient);
|
||||
|
||||
if (material != null) {
|
||||
return new ItemStack(material, 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ItemStack> getIngredients(int tier) {
|
||||
switch (tier) {
|
||||
case 8:
|
||||
return concoctionsIngredientsTierEight;
|
||||
case 7:
|
||||
return concoctionsIngredientsTierSeven;
|
||||
case 6:
|
||||
return concoctionsIngredientsTierSix;
|
||||
case 5:
|
||||
return concoctionsIngredientsTierFive;
|
||||
case 4:
|
||||
return concoctionsIngredientsTierFour;
|
||||
case 3:
|
||||
return concoctionsIngredientsTierThree;
|
||||
case 2:
|
||||
return concoctionsIngredientsTierTwo;
|
||||
case 1:
|
||||
default:
|
||||
return concoctionsIngredientsTierOne;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidPotion(ItemStack item) {
|
||||
return getPotion(item) != null;
|
||||
}
|
||||
|
||||
public AlchemyPotion getPotion(String name) {
|
||||
return potionMap.get(name);
|
||||
}
|
||||
|
||||
public AlchemyPotion getPotion(ItemStack item) {
|
||||
for (AlchemyPotion potion : potionMap.values()) {
|
||||
if (potion.isSimilar(item)) {
|
||||
return potion;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Color generateColor(List<PotionEffect> effects) {
|
||||
if (effects != null && !effects.isEmpty()) {
|
||||
List<Color> colors = new ArrayList<Color>();
|
||||
for (PotionEffect effect : effects) {
|
||||
if (effect.getType().getColor() != null) {
|
||||
colors.add(effect.getType().getColor());
|
||||
}
|
||||
}
|
||||
if (!colors.isEmpty()) {
|
||||
if (colors.size() > 1) {
|
||||
return calculateAverageColor(colors);
|
||||
}
|
||||
return colors.get(0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Color calculateAverageColor(List<Color> colors) {
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
for (Color color : colors) {
|
||||
red += color.getRed();
|
||||
green += color.getGreen();
|
||||
blue += color.getBlue();
|
||||
}
|
||||
Color color = Color.fromRGB(red / colors.size(), green / colors.size(), blue / colors.size());
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,357 @@
|
||||
package com.gmail.nossr50.core.config.treasure;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.Config;
|
||||
import com.gmail.nossr50.core.mcmmo.colors.ChatColor;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.skills.treasure.*;
|
||||
import com.gmail.nossr50.core.util.EnchantmentUtils;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class TreasureConfig extends Config {
|
||||
|
||||
private static TreasureConfig instance;
|
||||
|
||||
public HashMap<String, List<ExcavationTreasure>> excavationMap = new HashMap<String, List<ExcavationTreasure>>();
|
||||
|
||||
public HashMap<EntityType, List<ShakeTreasure>> shakeMap = new HashMap<EntityType, List<ShakeTreasure>>();
|
||||
public HashMap<String, List<HylianTreasure>> hylianMap = new HashMap<String, List<HylianTreasure>>();
|
||||
|
||||
public HashMap<Rarity, List<FishingTreasure>> fishingRewards = new HashMap<Rarity, List<FishingTreasure>>();
|
||||
public HashMap<Rarity, List<EnchantmentTreasure>> fishingEnchantments = new HashMap<Rarity, List<EnchantmentTreasure>>();
|
||||
|
||||
private TreasureConfig() {
|
||||
super(McmmoCore.getDataFolderPath().getAbsoluteFile(),"treasures.yml");
|
||||
loadKeys();
|
||||
validate();
|
||||
}
|
||||
|
||||
public static TreasureConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new TreasureConfig();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateKeys() {
|
||||
// Validate all the settings!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
for (String tier : config.getConfigurationSection("Enchantment_Drop_Rates").getKeys(false)) {
|
||||
double totalEnchantDropRate = 0;
|
||||
double totalItemDropRate = 0;
|
||||
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
double enchantDropRate = getDoubleValue("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
|
||||
double itemDropRate = getDoubleValue("Item_Drop_Rates." + tier + "." + rarity.toString());
|
||||
|
||||
if ((enchantDropRate < 0.0 || enchantDropRate > 100.0) && rarity != Rarity.RECORD) {
|
||||
reason.add("The enchant drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
if (itemDropRate < 0.0 || itemDropRate > 100.0) {
|
||||
reason.add("The item drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
totalEnchantDropRate += enchantDropRate;
|
||||
totalItemDropRate += itemDropRate;
|
||||
}
|
||||
|
||||
if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
|
||||
reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
|
||||
}
|
||||
|
||||
if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
|
||||
reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
|
||||
}
|
||||
}
|
||||
|
||||
return noErrorsInConfig(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadKeys() {
|
||||
if (config.getConfigurationSection("Treasures") != null) {
|
||||
backup();
|
||||
return;
|
||||
}
|
||||
|
||||
loadTreasures("Fishing");
|
||||
loadTreasures("Excavation");
|
||||
loadTreasures("Hylian_Luck");
|
||||
loadEnchantments();
|
||||
|
||||
for (EntityType entity : EntityType.values()) {
|
||||
if (entity.isAlive()) {
|
||||
loadTreasures("Shake." + entity.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTreasures(String type) {
|
||||
boolean isFishing = type.equals("Fishing");
|
||||
boolean isShake = type.contains("Shake");
|
||||
boolean isExcavation = type.equals("Excavation");
|
||||
boolean isHylian = type.equals("Hylian_Luck");
|
||||
|
||||
ConfigurationSection treasureSection = config.getConfigurationSection(type);
|
||||
|
||||
if (treasureSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize fishing HashMap
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
if (!fishingRewards.containsKey(rarity)) {
|
||||
fishingRewards.put(rarity, (new ArrayList<FishingTreasure>()));
|
||||
}
|
||||
}
|
||||
|
||||
for (String treasureName : treasureSection.getKeys(false)) {
|
||||
// Validate all the things!
|
||||
List<String> reason = new ArrayList<String>();
|
||||
|
||||
String[] treasureInfo = treasureName.split("[|]");
|
||||
String materialName = treasureInfo[0];
|
||||
|
||||
/*
|
||||
* Material, Amount, and Data
|
||||
*/
|
||||
Material material;
|
||||
|
||||
if (materialName.contains("INVENTORY")) {
|
||||
// Use magic material BEDROCK to know that we're grabbing something from the inventory and not a normal treasure
|
||||
if (!shakeMap.containsKey(EntityType.PLAYER))
|
||||
shakeMap.put(EntityType.PLAYER, new ArrayList<ShakeTreasure>());
|
||||
shakeMap.get(EntityType.PLAYER).add(new ShakeTreasure(new ItemStack(Material.BEDROCK, 1, (byte) 0), 1, getInventoryStealDropChance(), getInventoryStealDropLevel()));
|
||||
continue;
|
||||
} else {
|
||||
material = Material.matchMaterial(materialName);
|
||||
}
|
||||
|
||||
int amount = getIntValue(type + "." + treasureName + ".Amount");
|
||||
short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) : (short) getIntValue(type + "." + treasureName + ".Data");
|
||||
|
||||
if (material == null) {
|
||||
reason.add("Invalid material: " + materialName);
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
reason.add("Amount of " + treasureName + " must be greater than 0! " + amount);
|
||||
}
|
||||
|
||||
if (material != null && material.isBlock() && (data > 127 || data < -128)) {
|
||||
reason.add("Data of " + treasureName + " is invalid! " + data);
|
||||
}
|
||||
|
||||
/*
|
||||
* XP, Drop Chance, and Drop Level
|
||||
*/
|
||||
|
||||
int xp = getIntValue(type + "." + treasureName + ".XP");
|
||||
double dropChance = getDoubleValue(type + "." + treasureName + ".Drop_Chance");
|
||||
int dropLevel = getIntValue(type + "." + treasureName + ".Drop_Level");
|
||||
|
||||
if (xp < 0) {
|
||||
reason.add(treasureName + " has an invalid XP value: " + xp);
|
||||
}
|
||||
|
||||
if (dropChance < 0.0D) {
|
||||
reason.add(treasureName + " has an invalid Drop_Chance: " + dropChance);
|
||||
}
|
||||
|
||||
if (dropLevel < 0) {
|
||||
reason.add(treasureName + " has an invalid Drop_Level: " + dropLevel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Specific Types
|
||||
*/
|
||||
Rarity rarity = null;
|
||||
|
||||
if (isFishing) {
|
||||
rarity = Rarity.getRarity(getStringValue(type + "." + treasureName + ".Rarity"));
|
||||
|
||||
if (rarity == null) {
|
||||
reason.add("Invalid Rarity for item: " + treasureName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Itemstack
|
||||
*/
|
||||
ItemStack item = null;
|
||||
|
||||
if (materialName.contains("POTION")) {
|
||||
Material mat = Material.matchMaterial(materialName);
|
||||
if (mat == null) {
|
||||
reason.add("Potion format for Treasures.yml has changed");
|
||||
} else {
|
||||
item = new ItemStack(mat, amount, data);
|
||||
PotionMeta itemMeta = (PotionMeta) item.getItemMeta();
|
||||
|
||||
PotionType potionType = null;
|
||||
try {
|
||||
potionType = PotionType.valueOf(getStringValue(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
reason.add("Invalid Potion_Type: " + getStringValue(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
||||
}
|
||||
boolean extended = getBooleanValue(type + "." + treasureName + ".PotionData.Extended", false);
|
||||
boolean upgraded = getBooleanValue(type + "." + treasureName + ".PotionData.Upgraded", false);
|
||||
itemMeta.setBasePotionData(new PotionData(potionType, extended, upgraded));
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Custom_Name")) {
|
||||
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', getStringValue(type + "." + treasureName + ".Custom_Name")));
|
||||
}
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Lore")) {
|
||||
List<String> lore = new ArrayList<String>();
|
||||
for (String s : getStringValueList(type + "." + treasureName + ".Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
||||
}
|
||||
itemMeta.setLore(lore);
|
||||
}
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
} else if (material != null) {
|
||||
item = new ItemStack(material, amount, data);
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Custom_Name")) {
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', getStringValue(type + "." + treasureName + ".Custom_Name")));
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
|
||||
if (config.contains(type + "." + treasureName + ".Lore")) {
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
List<String> lore = new ArrayList<String>();
|
||||
for (String s : getStringValueList(type + "." + treasureName + ".Lore")) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
||||
}
|
||||
itemMeta.setLore(lore);
|
||||
item.setItemMeta(itemMeta);
|
||||
}
|
||||
}
|
||||
|
||||
if (noErrorsInConfig(reason)) {
|
||||
if (isFishing) {
|
||||
fishingRewards.get(rarity).add(new FishingTreasure(item, xp));
|
||||
} else if (isShake) {
|
||||
ShakeTreasure shakeTreasure = new ShakeTreasure(item, xp, dropChance, dropLevel);
|
||||
|
||||
EntityType entityType = EntityType.valueOf(type.substring(6));
|
||||
if (!shakeMap.containsKey(entityType))
|
||||
shakeMap.put(entityType, new ArrayList<ShakeTreasure>());
|
||||
shakeMap.get(entityType).add(shakeTreasure);
|
||||
} else if (isExcavation) {
|
||||
ExcavationTreasure excavationTreasure = new ExcavationTreasure(item, xp, dropChance, dropLevel);
|
||||
List<String> dropList = getStringValueList(type + "." + treasureName + ".Drops_From");
|
||||
|
||||
for (String blockType : dropList) {
|
||||
if (!excavationMap.containsKey(blockType))
|
||||
excavationMap.put(blockType, new ArrayList<ExcavationTreasure>());
|
||||
excavationMap.get(blockType).add(excavationTreasure);
|
||||
}
|
||||
} else if (isHylian) {
|
||||
HylianTreasure hylianTreasure = new HylianTreasure(item, xp, dropChance, dropLevel);
|
||||
List<String> dropList = getStringValueList(type + "." + treasureName + ".Drops_From");
|
||||
|
||||
for (String dropper : dropList) {
|
||||
if (dropper.equals("Bushes")) {
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.FERN), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.TALL_GRASS), hylianTreasure);
|
||||
for (Material species : Tag.SAPLINGS.getValues())
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure);
|
||||
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DEAD_BUSH), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
if (dropper.equals("Flowers")) {
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.POPPY), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.DANDELION), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.BLUE_ORCHID), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ALLIUM), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.AZURE_BLUET), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.ORANGE_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.PINK_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.RED_TULIP), hylianTreasure);
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(Material.WHITE_TULIP), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
if (dropper.equals("Pots")) {
|
||||
for (Material species : Tag.FLOWER_POTS.getValues())
|
||||
AddHylianTreasure(StringUtils.getFriendlyConfigMaterialString(species), hylianTreasure);
|
||||
continue;
|
||||
}
|
||||
AddHylianTreasure(dropper, hylianTreasure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddHylianTreasure(String dropper, HylianTreasure treasure) {
|
||||
if (!hylianMap.containsKey(dropper))
|
||||
hylianMap.put(dropper, new ArrayList<HylianTreasure>());
|
||||
hylianMap.get(dropper).add(treasure);
|
||||
}
|
||||
|
||||
private void loadEnchantments() {
|
||||
for (Rarity rarity : Rarity.values()) {
|
||||
if (rarity == Rarity.RECORD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fishingEnchantments.containsKey(rarity)) {
|
||||
fishingEnchantments.put(rarity, (new ArrayList<EnchantmentTreasure>()));
|
||||
}
|
||||
|
||||
ConfigurationSection enchantmentSection = config.getConfigurationSection("Enchantments_Rarity." + rarity.toString());
|
||||
|
||||
if (enchantmentSection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String enchantmentName : enchantmentSection.getKeys(false)) {
|
||||
int level = getIntValue("Enchantments_Rarity." + rarity.toString() + "." + enchantmentName);
|
||||
Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
|
||||
|
||||
if (enchantment == null) {
|
||||
plugin.getLogger().warning("Skipping invalid enchantment in treasures.yml: " + enchantmentName);
|
||||
continue;
|
||||
}
|
||||
|
||||
fishingEnchantments.get(rarity).add(new EnchantmentTreasure(enchantment, level));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getInventoryStealEnabled() {
|
||||
return config.contains("Shake.PLAYER.INVENTORY");
|
||||
}
|
||||
|
||||
public boolean getInventoryStealStacks() {
|
||||
return getBooleanValue("Shake.PLAYER.INVENTORY.Whole_Stacks");
|
||||
}
|
||||
|
||||
public double getInventoryStealDropChance() {
|
||||
return getDoubleValue("Shake.PLAYER.INVENTORY.Drop_Chance");
|
||||
}
|
||||
|
||||
public int getInventoryStealDropLevel() {
|
||||
return getIntValue("Shake.PLAYER.INVENTORY.Drop_Level");
|
||||
}
|
||||
|
||||
public double getItemDropRate(int tier, Rarity rarity) {
|
||||
return getDoubleValue("Item_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
||||
}
|
||||
|
||||
public double getEnchantmentDropRate(int tier, Rarity rarity) {
|
||||
return getDoubleValue("Enchantment_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
||||
}
|
||||
}
|
113
core/src/main/java/com/gmail/nossr50/core/data/UserManager.java
Normal file
113
core/src/main/java/com/gmail/nossr50/core/data/UserManager.java
Normal file
@ -0,0 +1,113 @@
|
||||
package com.gmail.nossr50.core.data;
|
||||
|
||||
import com.gmail.nossr50.core.datatypes.player.McMMOPlayer;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public final class UserManager {
|
||||
|
||||
private UserManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Track a new user.
|
||||
*
|
||||
* @param mcMMOPlayer the player profile to start tracking
|
||||
*/
|
||||
public static void track(McMMOPlayer mcMMOPlayer) {
|
||||
mcMMOPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mcMMOPlayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user.
|
||||
*
|
||||
* @param player The Player object
|
||||
*/
|
||||
public static void remove(Player player) {
|
||||
player.removeMetadata(mcMMO.playerDataKey, mcMMO.p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all users.
|
||||
*/
|
||||
public static void clearAll() {
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all users ON THIS THREAD.
|
||||
*/
|
||||
public static void saveAll() {
|
||||
ImmutableList<Player> onlinePlayers = ImmutableList.copyOf(mcMMO.p.getServer().getOnlinePlayers());
|
||||
mcMMO.p.debug("Saving mcMMOPlayers... (" + onlinePlayers.size() + ")");
|
||||
|
||||
for (Player player : onlinePlayers) {
|
||||
try {
|
||||
getPlayer(player).getProfile().save();
|
||||
} catch (Exception e) {
|
||||
mcMMO.p.getLogger().warning("Could not save mcMMO player data for player: " + player.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<McMMOPlayer> getPlayers() {
|
||||
Collection<McMMOPlayer> playerCollection = new ArrayList<McMMOPlayer>();
|
||||
|
||||
for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
|
||||
if (hasPlayerDataKey(player)) {
|
||||
playerCollection.add(getPlayer(player));
|
||||
}
|
||||
}
|
||||
|
||||
return playerCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the McMMOPlayer of a player by name.
|
||||
*
|
||||
* @param playerName The name of the player whose McMMOPlayer to retrieve
|
||||
* @return the player's McMMOPlayer object
|
||||
*/
|
||||
public static McMMOPlayer getPlayer(String playerName) {
|
||||
return retrieveMcMMOPlayer(playerName, false);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getOfflinePlayer(OfflinePlayer player) {
|
||||
if (player instanceof Player) {
|
||||
return getPlayer((Player) player);
|
||||
}
|
||||
|
||||
return retrieveMcMMOPlayer(player.getName(), true);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getOfflinePlayer(String playerName) {
|
||||
return retrieveMcMMOPlayer(playerName, true);
|
||||
}
|
||||
|
||||
public static McMMOPlayer getPlayer(Player player) {
|
||||
return (McMMOPlayer) player.getMetadata(mcMMO.playerDataKey).get(0).value();
|
||||
}
|
||||
|
||||
private static McMMOPlayer retrieveMcMMOPlayer(String playerName, boolean offlineValid) {
|
||||
Player player = mcMMO.p.getServer().getPlayerExact(playerName);
|
||||
|
||||
if (player == null) {
|
||||
if (!offlineValid) {
|
||||
mcMMO.p.getLogger().warning("A valid mcMMOPlayer object could not be found for " + playerName + ".");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return getPlayer(player);
|
||||
}
|
||||
|
||||
public static boolean hasPlayerDataKey(Entity entity) {
|
||||
return entity != null && entity.hasMetadata(mcMMO.playerDataKey);
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.block.Block;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
public interface ChunkletManager {
|
||||
/**
|
||||
* Loads a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be loaded
|
||||
* @param cy Chunklet Y coordinate that needs to be loaded
|
||||
* @param cz Chunklet Z coordinate that needs to be loaded
|
||||
* @param world World that the chunklet needs to be loaded in
|
||||
*/
|
||||
public void loadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be unloaded
|
||||
* @param cy Chunklet Y coordinate that needs to be unloaded
|
||||
* @param cz Chunklet Z coordinate that needs to be unloaded
|
||||
* @param world World that the chunklet needs to be unloaded from
|
||||
*/
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Load a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be loaded
|
||||
* @param cz Chunk Z coordinate that is to be loaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void loadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be unloaded
|
||||
* @param cz Chunk Z coordinate that is to be unloaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void unloadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is loaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is loaded
|
||||
* @param cz Chunk Z coordinate that is loaded
|
||||
* @param world World that the chunk was loaded in
|
||||
*/
|
||||
public void chunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is unloaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is unloaded
|
||||
* @param cz Chunk Z coordinate that is unloaded
|
||||
* @param world World that the chunk was unloaded in
|
||||
*/
|
||||
public void chunkUnloaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores related to the given world
|
||||
*
|
||||
* @param world World to save
|
||||
*/
|
||||
public void saveWorld(World world);
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
||||
*
|
||||
* @param world World to unload
|
||||
*/
|
||||
public void unloadWorld(World world);
|
||||
|
||||
/**
|
||||
* Load all ChunkletStores from all loaded chunks from this world into memory
|
||||
*
|
||||
* @param world World to load
|
||||
*/
|
||||
public void loadWorld(World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores
|
||||
*/
|
||||
public void saveAll();
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores after saving them
|
||||
*/
|
||||
public void unloadAll();
|
||||
|
||||
/**
|
||||
* Check to see if a given location is set to true
|
||||
*
|
||||
* @param x X coordinate to check
|
||||
* @param y Y coordinate to check
|
||||
* @param z Z coordinate to check
|
||||
* @param world World to check in
|
||||
* @return true if the given location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Check to see if a given block location is set to true
|
||||
*
|
||||
* @param block Block location to check
|
||||
* @return true if the given block location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setFalse(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setFalse(Block block);
|
||||
|
||||
/**
|
||||
* Delete any ChunkletStores that are empty
|
||||
*/
|
||||
public void cleanUp();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import com.gmail.nossr50.core.config.ChunkConversionOptions;
|
||||
|
||||
public class ChunkletManagerFactory {
|
||||
public static ChunkletManager getChunkletManager() {
|
||||
ChunkConversionOptions hConfig = ChunkConversionOptions.getInstance();
|
||||
|
||||
if (hConfig.getChunkletsEnabled()) {
|
||||
return new HashChunkletManager();
|
||||
}
|
||||
|
||||
return new NullChunkletManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A ChunkletStore should be responsible for a 16x16x64 area of data
|
||||
*/
|
||||
public interface ChunkletStore extends Serializable {
|
||||
/**
|
||||
* Checks the value at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
* @return true if the value is true at the given coordinates, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to true at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to false at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setFalse(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* @return true if all values in the chunklet are false, false if otherwise
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Set all values in this ChunkletStore to the values from another provided ChunkletStore
|
||||
*
|
||||
* @param otherStore Another ChunkletStore that this one should copy all data from
|
||||
*/
|
||||
public void copyFrom(ChunkletStore otherStore);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
public class ChunkletStoreFactory {
|
||||
protected static ChunkletStore getChunkletStore() {
|
||||
// TODO: Add in loading from config what type of store we want.
|
||||
return new PrimitiveExChunkletStore();
|
||||
}
|
||||
}
|
@ -0,0 +1,398 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.block.Block;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class HashChunkletManager implements ChunkletManager {
|
||||
public HashMap<String, ChunkletStore> store = new HashMap<String, ChunkletStore>();
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File yFile = new File(czDir, "" + cy);
|
||||
if (!yFile.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChunkletStore in = deserializeChunkletStore(yFile);
|
||||
if (in != null) {
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + cy, in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz + "," + cy)) {
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
File yFile = new File(czDir, "" + cy);
|
||||
|
||||
ChunkletStore out = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
serializeChunkletStore(out, yFile);
|
||||
store.remove(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 4; y++) {
|
||||
File yFile = new File(czDir, "" + y);
|
||||
if (!yFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChunkletStore in = deserializeChunkletStore(yFile);
|
||||
if (in != null) {
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + y, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
|
||||
for (int y = 0; y < 4; y++) {
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz + "," + y)) {
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
File yFile = new File(czDir, "" + y);
|
||||
|
||||
ChunkletStore out = store.get(world.getName() + "," + cx + "," + cz + "," + y);
|
||||
serializeChunkletStore(out, yFile);
|
||||
store.remove(world.getName() + "," + cx + "," + cz + "," + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {
|
||||
//loadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {
|
||||
unloadChunk(cx, cx, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {
|
||||
String worldName = world.getName();
|
||||
File dataDir = new File(world.getWorldFolder(), "mcmmo_data");
|
||||
if (!dataDir.exists()) {
|
||||
dataDir.mkdirs();
|
||||
}
|
||||
|
||||
for (String key : store.keySet()) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
File cxDir = new File(dataDir, "" + info[1]);
|
||||
if (!cxDir.exists()) {
|
||||
cxDir.mkdir();
|
||||
}
|
||||
File czDir = new File(cxDir, "" + info[2]);
|
||||
if (!czDir.exists()) {
|
||||
czDir.mkdir();
|
||||
}
|
||||
|
||||
File yFile = new File(czDir, "" + info[3]);
|
||||
serializeChunkletStore(store.get(key), yFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {
|
||||
saveWorld(world);
|
||||
|
||||
String worldName = world.getName();
|
||||
|
||||
for (String key : store.keySet()) {
|
||||
String tempWorldName = key.split(",")[0];
|
||||
if (tempWorldName.equals(worldName)) {
|
||||
store.remove(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {
|
||||
//for (Chunk chunk : world.getLoadedChunks()) {
|
||||
// this.chunkLoaded(chunk.getX(), chunk.getZ(), world);
|
||||
//}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
saveWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {
|
||||
saveAll();
|
||||
for (World world : mcMMO.p.getServer().getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkletStore check = store.get(world.getName() + "," + cx + "," + cz + "," + cy);
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
return check.isTrue(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
ChunkletStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
cStore = ChunkletStoreFactory.getChunkletStore();
|
||||
|
||||
store.put(world.getName() + "," + cx + "," + cz + "," + cy, cStore);
|
||||
}
|
||||
|
||||
cStore.setTrue(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {
|
||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cy = y >> 6;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
int iy = Math.abs(y) % 64;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz + "," + cy;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunklet(cx, cy, cz, world);
|
||||
}
|
||||
|
||||
ChunkletStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
return; // No need to make a store for something we will be setting to false
|
||||
}
|
||||
|
||||
cStore.setFalse(ix, iy, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {
|
||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
for (String key : store.keySet()) {
|
||||
if (store.get(key).isEmpty()) {
|
||||
String[] info = key.split(",");
|
||||
File dataDir = new File(mcMMO.p.getServer().getWorld(info[0]).getWorldFolder(), "mcmmo_data");
|
||||
|
||||
File cxDir = new File(dataDir, "" + info[1]);
|
||||
if (!cxDir.exists()) {
|
||||
continue;
|
||||
}
|
||||
File czDir = new File(cxDir, "" + info[2]);
|
||||
if (!czDir.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
File yFile = new File(czDir, "" + info[3]);
|
||||
yFile.delete();
|
||||
|
||||
// Delete empty directories
|
||||
if (czDir.list().length == 0) {
|
||||
czDir.delete();
|
||||
}
|
||||
if (cxDir.list().length == 0) {
|
||||
cxDir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cStore ChunkletStore to save
|
||||
* @param location Where on the disk to put it
|
||||
*/
|
||||
private void serializeChunkletStore(ChunkletStore cStore, File location) {
|
||||
FileOutputStream fileOut = null;
|
||||
ObjectOutputStream objOut = null;
|
||||
|
||||
try {
|
||||
if (!location.exists()) {
|
||||
location.createNewFile();
|
||||
}
|
||||
fileOut = new FileOutputStream(location);
|
||||
objOut = new ObjectOutputStream(fileOut);
|
||||
objOut.writeObject(cStore);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (objOut != null) {
|
||||
try {
|
||||
objOut.flush();
|
||||
objOut.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (fileOut != null) {
|
||||
try {
|
||||
fileOut.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location Where on the disk to read from
|
||||
* @return ChunkletStore from the specified location
|
||||
*/
|
||||
private ChunkletStore deserializeChunkletStore(File location) {
|
||||
ChunkletStore storeIn = null;
|
||||
FileInputStream fileIn = null;
|
||||
ObjectInputStream objIn = null;
|
||||
|
||||
try {
|
||||
fileIn = new FileInputStream(location);
|
||||
objIn = new ObjectInputStream(fileIn);
|
||||
storeIn = (ChunkletStore) objIn.readObject();
|
||||
} catch (IOException ex) {
|
||||
if (ex instanceof EOFException) {
|
||||
// EOF should only happen on Chunklets that somehow have been corrupted.
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " could not be read due to an EOFException, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
} else if (ex instanceof StreamCorruptedException) {
|
||||
// StreamCorrupted happens when the Chunklet is no good.
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " is corrupted, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
} else if (ex instanceof UTFDataFormatException) {
|
||||
// UTF happens when the Chunklet cannot be read or is corrupted
|
||||
//mcMMO.p.getLogger().severe("Chunklet data at " + location.toString() + " could not be read due to an UTFDataFormatException, data in this area will be lost.");
|
||||
return ChunkletStoreFactory.getChunkletStore();
|
||||
}
|
||||
|
||||
ex.printStackTrace();
|
||||
} catch (ClassNotFoundException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (objIn != null) {
|
||||
try {
|
||||
objIn.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (fileIn != null) {
|
||||
try {
|
||||
fileIn.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make this less messy, as it is, it's kinda... depressing to do it like this.
|
||||
// Might also make a mess when we move to stacks, but at that point I think I will write a new Manager...
|
||||
// IMPORTANT! If ChunkletStoreFactory is going to be returning something other than PrimitiveEx we need to remove this, as it will be breaking time for old maps
|
||||
|
||||
/*
|
||||
if (!(storeIn instanceof PrimitiveExChunkletStore)) {
|
||||
ChunkletStore tempStore = ChunkletStoreFactory.getChunkletStore();
|
||||
if (storeIn != null) {
|
||||
tempStore.copyFrom(storeIn);
|
||||
}
|
||||
storeIn = tempStore;
|
||||
}
|
||||
*/
|
||||
|
||||
return storeIn;
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
/**
|
||||
* A ChunkletManager implementation that does nothing and returns false for all checks.
|
||||
* <p>
|
||||
* Useful for turning off Chunklets without actually doing much work
|
||||
*/
|
||||
public class NullChunkletManager implements ChunkletManager {
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
public class PrimitiveChunkletStore implements ChunkletStore {
|
||||
private static final long serialVersionUID = -3453078050608607478L;
|
||||
|
||||
/**
|
||||
* X, Z, Y
|
||||
*/
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
store[x][z][y] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
store[x][z][y] = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
public class PrimitiveExChunkletStore implements ChunkletStore, Externalizable {
|
||||
private static final long serialVersionUID = 8603603827094383873L;
|
||||
|
||||
/**
|
||||
* X, Z, Y
|
||||
*/
|
||||
public boolean[][][] store = new boolean[16][16][64];
|
||||
|
||||
/*
|
||||
* The address byte: A single byte which contains x and z values which correspond to the x and z Chunklet-coordinates
|
||||
*
|
||||
* In Chunklet-coordinates, the only valid values are 0-15, so we can fit both into a single byte.
|
||||
*
|
||||
* The top 4 bits of the address byte are for the x value
|
||||
* The bottom 4 bits of the address byte are for the z value
|
||||
*
|
||||
* Examples:
|
||||
* An address byte with a value 00000001 would be split like so:
|
||||
* - x = 0000 = 0
|
||||
* - z = 0001 = 1
|
||||
* => Chunklet coordinates (0, 1)
|
||||
*
|
||||
* 01011111
|
||||
* - x = 0101 = 5
|
||||
* - z = 1111 = 15
|
||||
* => Chunklet coordinates (5, 15)
|
||||
*/
|
||||
protected static byte makeAddressByte(int x, int z) {
|
||||
return (byte) ((x << 4) + z);
|
||||
}
|
||||
|
||||
protected static int addressByteX(byte address) {
|
||||
return (address & 0xF0) >>> 4;
|
||||
}
|
||||
|
||||
protected static int addressByteZ(byte address) {
|
||||
return address & 0x0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
store[x][z][y] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
store[x][z][y] = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
byte[] buffer = new byte[2304]; // 2304 is 16*16*9
|
||||
int bufferIndex = 0;
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 64; y++) {
|
||||
if (store[x][z][y]) {
|
||||
byte[] temp = constructColumn(x, z);
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
buffer[bufferIndex] = temp[i];
|
||||
bufferIndex++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.write(buffer, 0, bufferIndex);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
// For this we assume that store has been initialized to be all false by now
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException {
|
||||
byte[] temp = new byte[9];
|
||||
|
||||
// Could probably reorganize this loop to print nasty things if it does not equal 9 or -1
|
||||
while (in.read(temp, 0, 9) == 9) {
|
||||
int x = addressByteX(temp[0]);
|
||||
int z = addressByteZ(temp[0]);
|
||||
boolean[] yColumn = new boolean[64];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
yColumn[j + (i * 8)] = (temp[i + 1] & (1 << j)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
store[x][z] = yColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The column: An array of 9 bytes which represent all y values for a given (x,z) Chunklet-coordinate
|
||||
*
|
||||
* The first byte is an address byte, this provides the x and z values.
|
||||
* The next 8 bytes are all y values from 0 to 63, with each byte containing 8 bits of true/false data
|
||||
*
|
||||
* Each of these 8 bytes address to a y value from right to left
|
||||
*
|
||||
* Examples:
|
||||
* 00000001 represents that the lowest y value in this byte is true, all others are off
|
||||
* 10000000 represents that the highest y value in this byte is true, all others are off
|
||||
* 10000001 represents that the lowest and highest y values in this byte are true, all others are off
|
||||
*
|
||||
* Full columns:
|
||||
* See comment on Address byte for information on how to use that byte
|
||||
*
|
||||
* Example:
|
||||
* ADDRESS_BYTE 10000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000
|
||||
* - x, z from ADDRESS_BYTE
|
||||
* - The next byte contains data from 0 to 7
|
||||
* - 1 is set in the highest bit position, this is 7 in y coordinate
|
||||
* - The next byte contains data from 8 to 15
|
||||
* - 1 is set in the lowest bit position, this is 8 in the y coordinate
|
||||
* Therefore, for this column: There are true values at (x, 7, z) and (x, 8, z)
|
||||
*/
|
||||
private byte[] constructColumn(int x, int z) {
|
||||
byte[] column = new byte[9];
|
||||
int index = 1;
|
||||
|
||||
column[0] = makeAddressByte(x, z);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
byte yCompressed = 0x0;
|
||||
int subColumnIndex = 8 * i;
|
||||
int subColumnEnd = subColumnIndex + 8;
|
||||
|
||||
for (int y = subColumnIndex; y < subColumnEnd; y++) {
|
||||
if (store[x][z][y]) {
|
||||
yCompressed |= 1 << (y % 8);
|
||||
}
|
||||
}
|
||||
|
||||
column[index] = yCompressed;
|
||||
index++;
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.block.Block;
|
||||
import com.gmail.nossr50.core.mcmmo.block.BlockState;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Entity;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ChunkManager {
|
||||
public void closeAll();
|
||||
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException;
|
||||
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data);
|
||||
|
||||
public void closeChunkStore(World world, int x, int z);
|
||||
|
||||
/**
|
||||
* Loads a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be loaded
|
||||
* @param cy Chunklet Y coordinate that needs to be loaded
|
||||
* @param cz Chunklet Z coordinate that needs to be loaded
|
||||
* @param world World that the chunklet needs to be loaded in
|
||||
*/
|
||||
public void loadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Unload a specific chunklet
|
||||
*
|
||||
* @param cx Chunklet X coordinate that needs to be unloaded
|
||||
* @param cy Chunklet Y coordinate that needs to be unloaded
|
||||
* @param cz Chunklet Z coordinate that needs to be unloaded
|
||||
* @param world World that the chunklet needs to be unloaded from
|
||||
*/
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world);
|
||||
|
||||
/**
|
||||
* Load a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be loaded
|
||||
* @param cz Chunk Z coordinate that is to be loaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void loadChunk(int cx, int cz, World world, Entity[] entities);
|
||||
|
||||
/**
|
||||
* Unload a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be unloaded
|
||||
* @param cz Chunk Z coordinate that is to be unloaded
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void unloadChunk(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Saves a given Chunk's Chunklet data
|
||||
*
|
||||
* @param cx Chunk X coordinate that is to be saved
|
||||
* @param cz Chunk Z coordinate that is to be saved
|
||||
* @param world World that the Chunk is in
|
||||
*/
|
||||
public void saveChunk(int cx, int cz, World world);
|
||||
|
||||
public boolean isChunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is loaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is loaded
|
||||
* @param cz Chunk Z coordinate that is loaded
|
||||
* @param world World that the chunk was loaded in
|
||||
*/
|
||||
public void chunkLoaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Informs the ChunkletManager a chunk is unloaded
|
||||
*
|
||||
* @param cx Chunk X coordinate that is unloaded
|
||||
* @param cz Chunk Z coordinate that is unloaded
|
||||
* @param world World that the chunk was unloaded in
|
||||
*/
|
||||
public void chunkUnloaded(int cx, int cz, World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores related to the given world
|
||||
*
|
||||
* @param world World to save
|
||||
*/
|
||||
public void saveWorld(World world);
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores from memory related to the given world after saving them
|
||||
*
|
||||
* @param world World to unload
|
||||
*/
|
||||
public void unloadWorld(World world);
|
||||
|
||||
/**
|
||||
* Load all ChunkletStores from all loaded chunks from this world into memory
|
||||
*
|
||||
* @param world World to load
|
||||
*/
|
||||
public void loadWorld(World world);
|
||||
|
||||
/**
|
||||
* Save all ChunkletStores
|
||||
*/
|
||||
public void saveAll();
|
||||
|
||||
/**
|
||||
* Unload all ChunkletStores after saving them
|
||||
*/
|
||||
public void unloadAll();
|
||||
|
||||
/**
|
||||
* Check to see if a given location is set to true
|
||||
*
|
||||
* @param x X coordinate to check
|
||||
* @param y Y coordinate to check
|
||||
* @param z Z coordinate to check
|
||||
* @param world World to check in
|
||||
* @return true if the given location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Check to see if a given block location is set to true
|
||||
*
|
||||
* @param block Block location to check
|
||||
* @return true if the given block location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(Block block);
|
||||
|
||||
/**
|
||||
* Check to see if a given BlockState location is set to true
|
||||
*
|
||||
* @param blockState BlockState to check
|
||||
* @return true if the given BlockState location is set to true, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Set a given location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setTrue(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setTrue(Block block);
|
||||
|
||||
/**
|
||||
* Set a given BlockState location to true, should create stores as necessary if the location does not exist
|
||||
*
|
||||
* @param blockState BlockState location to set
|
||||
*/
|
||||
public void setTrue(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Set a given location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param x X coordinate to set
|
||||
* @param y Y coordinate to set
|
||||
* @param z Z coordinate to set
|
||||
* @param world World to set in
|
||||
*/
|
||||
public void setFalse(int x, int y, int z, World world);
|
||||
|
||||
/**
|
||||
* Set a given block location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param block Block location to set
|
||||
*/
|
||||
public void setFalse(Block block);
|
||||
|
||||
/**
|
||||
* Set a given BlockState location to false, should not create stores if one does not exist for the given location
|
||||
*
|
||||
* @param blockState BlockState location to set
|
||||
*/
|
||||
public void setFalse(BlockState blockState);
|
||||
|
||||
/**
|
||||
* Delete any ChunkletStores that are empty
|
||||
*/
|
||||
public void cleanUp();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.config.ChunkConversionOptions;
|
||||
|
||||
public class ChunkManagerFactory {
|
||||
public static ChunkManager getChunkManager() {
|
||||
ChunkConversionOptions hConfig = ChunkConversionOptions.getInstance();
|
||||
|
||||
if (hConfig.getChunkletsEnabled()) {
|
||||
return new HashChunkManager();
|
||||
}
|
||||
|
||||
return new NullChunkManager();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A ChunkStore should be responsible for a 16x16xWorldHeight area of data
|
||||
*/
|
||||
public interface ChunkStore extends Serializable {
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @return true if the has been modified since it was last saved
|
||||
*/
|
||||
public boolean isDirty();
|
||||
|
||||
/**
|
||||
* Checks the chunk's save state
|
||||
*
|
||||
* @param dirty the save state of the current chunk
|
||||
*/
|
||||
public void setDirty(boolean dirty);
|
||||
|
||||
/**
|
||||
* Checks the chunk's x coordinate
|
||||
*
|
||||
* @return the chunk's x coordinate.
|
||||
*/
|
||||
public int getChunkX();
|
||||
|
||||
/**
|
||||
* Checks the chunk's z coordinate
|
||||
*
|
||||
* @return the chunk's z coordinate.
|
||||
*/
|
||||
public int getChunkZ();
|
||||
|
||||
/**
|
||||
* Checks the value at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
* @return true if the value is true at the given coordinates, false if otherwise
|
||||
*/
|
||||
public boolean isTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to true at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setTrue(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set the value to false at the given coordinates
|
||||
*
|
||||
* @param x x coordinate in current chunklet
|
||||
* @param y y coordinate in current chunklet
|
||||
* @param z z coordinate in current chunklet
|
||||
*/
|
||||
public void setFalse(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* @return true if all values in the chunklet are false, false if otherwise
|
||||
*/
|
||||
public boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Set all values in this ChunkletStore to the values from another provided ChunkletStore
|
||||
*
|
||||
* @param otherStore Another ChunkletStore that this one should copy all data from
|
||||
*/
|
||||
public void copyFrom(ChunkletStore otherStore);
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
public class ChunkStoreFactory {
|
||||
protected static ChunkStore getChunkStore(World world, int x, int z) {
|
||||
// TODO: Add in loading from config what type of store we want.
|
||||
return new PrimitiveChunkStore(world, x, z);
|
||||
}
|
||||
}
|
@ -0,0 +1,459 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.conversion.BlockStoreConversionZDirectory;
|
||||
import com.gmail.nossr50.core.mcmmo.block.Block;
|
||||
import com.gmail.nossr50.core.mcmmo.block.BlockState;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Entity;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class HashChunkManager implements ChunkManager {
|
||||
public HashMap<String, ChunkStore> store = new HashMap<String, ChunkStore>();
|
||||
public ArrayList<BlockStoreConversionZDirectory> converters = new ArrayList<BlockStoreConversionZDirectory>();
|
||||
private HashMap<UUID, HashMap<Long, McMMOSimpleRegionFile>> regionFiles = new HashMap<UUID, HashMap<Long, McMMOSimpleRegionFile>>();
|
||||
private HashMap<UUID, Boolean> oldData = new HashMap<UUID, Boolean>();
|
||||
|
||||
@Override
|
||||
public synchronized void closeAll() {
|
||||
for (UUID uid : regionFiles.keySet()) {
|
||||
HashMap<Long, McMMOSimpleRegionFile> worldRegions = regionFiles.get(uid);
|
||||
for (Iterator<McMMOSimpleRegionFile> worldRegionIterator = worldRegions.values().iterator(); worldRegionIterator.hasNext(); ) {
|
||||
McMMOSimpleRegionFile rf = worldRegionIterator.next();
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
worldRegionIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
regionFiles.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
InputStream in = rf.getInputStream(x, z);
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
ObjectInputStream objectStream = new ObjectInputStream(in);
|
||||
try {
|
||||
Object o = objectStream.readObject();
|
||||
if (o instanceof ChunkStore) {
|
||||
return (ChunkStore) o;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Wrong class type read for chunk meta data for " + x + ", " + z);
|
||||
} catch (IOException e) {
|
||||
// Assume the format changed
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to process chunk meta data for " + x + ", " + z, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Assume the format changed
|
||||
//System.out.println("[SpoutPlugin] is Unable to find serialized class for " + x + ", " + z + ", " + e.getMessage());
|
||||
return null;
|
||||
//throw new RuntimeException("Unable to find serialized class for " + x + ", " + z, e);
|
||||
} finally {
|
||||
objectStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void writeChunkStore(World world, int x, int z, ChunkStore data) {
|
||||
if (!data.isDirty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
ObjectOutputStream objectStream = new ObjectOutputStream(rf.getOutputStream(x, z));
|
||||
objectStream.writeObject(data);
|
||||
objectStream.flush();
|
||||
objectStream.close();
|
||||
data.setDirty(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to write chunk meta data for " + x + ", " + z, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeChunkStore(World world, int x, int z) {
|
||||
McMMOSimpleRegionFile rf = getSimpleRegionFile(world, x, z);
|
||||
if (rf != null) {
|
||||
rf.close();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized McMMOSimpleRegionFile getSimpleRegionFile(World world, int x, int z) {
|
||||
File directory = new File(world.getWorldFolder(), "mcmmo_regions");
|
||||
|
||||
directory.mkdirs();
|
||||
|
||||
UUID key = world.getUUID();
|
||||
|
||||
HashMap<Long, McMMOSimpleRegionFile> worldRegions = regionFiles.get(key);
|
||||
|
||||
if (worldRegions == null) {
|
||||
worldRegions = new HashMap<Long, McMMOSimpleRegionFile>();
|
||||
regionFiles.put(key, worldRegions);
|
||||
}
|
||||
|
||||
int rx = x >> 5;
|
||||
int rz = z >> 5;
|
||||
|
||||
long key2 = (((long) rx) << 32) | ((rz) & 0xFFFFFFFFL);
|
||||
|
||||
McMMOSimpleRegionFile regionFile = worldRegions.get(key2);
|
||||
|
||||
if (regionFile == null) {
|
||||
File file = new File(directory, "mcmmo_" + rx + "_" + rz + "_.mcm");
|
||||
regionFile = new McMMOSimpleRegionFile(file, rx, rz);
|
||||
worldRegions.put(key2, regionFile);
|
||||
}
|
||||
|
||||
return regionFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadChunk(int cx, int cz, World world, Entity[] entities) {
|
||||
if (world == null || store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID key = world.getUUID();
|
||||
|
||||
if (!oldData.containsKey(key)) {
|
||||
oldData.put(key, (new File(world.getWorldFolder(), "mcmmo_data")).exists());
|
||||
} else if (oldData.get(key)) {
|
||||
if (convertChunk(new File(world.getWorldFolder(), "mcmmo_data"), cx, cz, world, true)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChunkStore chunkStore = null;
|
||||
|
||||
try {
|
||||
chunkStore = readChunkStore(world, cx, cz);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (chunkStore == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.put(world.getName() + "," + cx + "," + cz, chunkStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadChunk(int cx, int cz, World world) {
|
||||
saveChunk(cx, cz, world);
|
||||
|
||||
if (store.containsKey(world.getName() + "," + cx + "," + cz)) {
|
||||
store.remove(world.getName() + "," + cx + "," + cz);
|
||||
|
||||
//closeChunkStore(world, cx, cz);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveChunk(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (store.containsKey(key)) {
|
||||
ChunkStore out = store.get(world.getName() + "," + cx + "," + cz);
|
||||
|
||||
if (!out.isDirty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeChunkStore(world, cx, cz, out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return store.containsKey(world.getName() + "," + cx + "," + cz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkLoaded(int cx, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void chunkUnloaded(int cx, int cz, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
unloadChunk(cx, cz, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveWorld(World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
List<String> keys = new ArrayList<String>(store.keySet());
|
||||
for (String key : keys) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
try {
|
||||
saveChunk(Integer.parseInt(info[1]), Integer.parseInt(info[2]), world);
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadWorld(World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeAll();
|
||||
String worldName = world.getName();
|
||||
|
||||
List<String> keys = new ArrayList<String>(store.keySet());
|
||||
for (String key : keys) {
|
||||
String[] info = key.split(",");
|
||||
if (worldName.equals(info[0])) {
|
||||
try {
|
||||
unloadChunk(Integer.parseInt(info[1]), Integer.parseInt(info[2]), world);
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void loadWorld(World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void saveAll() {
|
||||
closeAll();
|
||||
|
||||
for (World world : McmmoCore.getServer().getWorlds()) {
|
||||
saveWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unloadAll() {
|
||||
closeAll();
|
||||
|
||||
for (World world : McmmoCore.getServer().getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkStore check = store.get(key);
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
return check.isTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(Block block) {
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isTrue(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isTrue(blockState.getBlock().getX(), blockState.getBlock().getY(), blockState.getBlock().getZ(), blockState.getBlock().getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
cStore = ChunkStoreFactory.getChunkStore(world, cx, cz);
|
||||
store.put(key, cStore);
|
||||
}
|
||||
|
||||
cStore.setTrue(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setTrue(Block block) {
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTrue(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTrue(blockState.getBlock().getX(), blockState.getBlock().getY(), blockState.getBlock().getZ(), blockState.getBlock().getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(int x, int y, int z, World world) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
|
||||
int ix = Math.abs(x) % 16;
|
||||
int iz = Math.abs(z) % 16;
|
||||
|
||||
String key = world.getName() + "," + cx + "," + cz;
|
||||
|
||||
if (!store.containsKey(key)) {
|
||||
loadChunk(cx, cz, world, null);
|
||||
}
|
||||
|
||||
ChunkStore cStore = store.get(key);
|
||||
|
||||
if (cStore == null) {
|
||||
return; // No need to make a store for something we will be setting to false
|
||||
}
|
||||
|
||||
cStore.setFalse(ix, y, iz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(Block block) {
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFalse(block.getX(), block.getY(), block.getZ(), block.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setFalse(BlockState blockState) {
|
||||
if (blockState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
setFalse(blockState.getBlock().getX(), blockState.getBlock().getY(), blockState.getBlock().getZ(), blockState.getBlock().getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cleanUp() {
|
||||
}
|
||||
|
||||
public synchronized void convertChunk(File dataDir, int cx, int cz, World world) {
|
||||
convertChunk(dataDir, cx, cz, world, false);
|
||||
}
|
||||
|
||||
public synchronized boolean convertChunk(File dataDir, int cx, int cz, World world, boolean actually) {
|
||||
if (!actually || !dataDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File cxDir = new File(dataDir, "" + cx);
|
||||
if (!cxDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File czDir = new File(cxDir, "" + cz);
|
||||
if (!czDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean conversionSet = false;
|
||||
|
||||
for (BlockStoreConversionZDirectory converter : this.converters) {
|
||||
if (converter == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (converter.taskID >= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
converter.start(world, cxDir, czDir);
|
||||
conversionSet = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!conversionSet) {
|
||||
BlockStoreConversionZDirectory converter = new BlockStoreConversionZDirectory();
|
||||
converter.start(world, cxDir, czDir);
|
||||
converters.add(converter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class McMMOSimpleChunkBuffer extends ByteArrayOutputStream {
|
||||
final McMMOSimpleRegionFile rf;
|
||||
final int index;
|
||||
|
||||
McMMOSimpleChunkBuffer(McMMOSimpleRegionFile rf, int index) {
|
||||
super(1024);
|
||||
this.rf = rf;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
rf.write(index, buf, count);
|
||||
}
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* This file is part of SpoutPlugin.
|
||||
*
|
||||
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/>
|
||||
* SpoutPlugin is licensed under the GNU Lesser General Public License.
|
||||
*
|
||||
* SpoutPlugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SpoutPlugin is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public class McMMOSimpleRegionFile {
|
||||
@SuppressWarnings("unused")
|
||||
private static long TIMEOUT_TIME = 300000; // 5 min
|
||||
private final int[] dataStart = new int[1024];
|
||||
private final int[] dataActualLength = new int[1024];
|
||||
private final int[] dataLength = new int[1024];
|
||||
private final ArrayList<Boolean> inuse = new ArrayList<Boolean>();
|
||||
private final int rx;
|
||||
private final int rz;
|
||||
private final int defaultSegmentSize;
|
||||
private final File parent;
|
||||
private RandomAccessFile file;
|
||||
private int segmentSize;
|
||||
private int segmentMask;
|
||||
@SuppressWarnings("unused")
|
||||
private long lastAccessTime = System.currentTimeMillis();
|
||||
|
||||
public McMMOSimpleRegionFile(File f, int rx, int rz) {
|
||||
this(f, rx, rz, 10);
|
||||
}
|
||||
|
||||
public McMMOSimpleRegionFile(File f, int rx, int rz, int defaultSegmentSize) {
|
||||
this.rx = rx;
|
||||
this.rz = rz;
|
||||
this.defaultSegmentSize = defaultSegmentSize;
|
||||
this.parent = f;
|
||||
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
} catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized final RandomAccessFile getFile() {
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
if (file == null) {
|
||||
try {
|
||||
this.file = new RandomAccessFile(parent, "rw");
|
||||
|
||||
if (file.length() < 4096 * 3) {
|
||||
for (int i = 0; i < 1024 * 3; i++) {
|
||||
file.writeInt(0);
|
||||
}
|
||||
file.seek(4096 * 2);
|
||||
file.writeInt(defaultSegmentSize);
|
||||
}
|
||||
|
||||
file.seek(4096 * 2);
|
||||
|
||||
this.segmentSize = file.readInt();
|
||||
this.segmentMask = (1 << segmentSize) - 1;
|
||||
|
||||
int reservedSegments = this.sizeToSegments(4096 * 3);
|
||||
|
||||
for (int i = 0; i < reservedSegments; i++) {
|
||||
while (inuse.size() <= i) {
|
||||
inuse.add(false);
|
||||
}
|
||||
inuse.set(i, true);
|
||||
}
|
||||
|
||||
file.seek(0);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataStart[i] = file.readInt();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
dataActualLength[i] = file.readInt();
|
||||
dataLength[i] = sizeToSegments(dataActualLength[i]);
|
||||
setInUse(i, true);
|
||||
}
|
||||
|
||||
extendFile();
|
||||
} catch (IOException fnfe) {
|
||||
throw new RuntimeException(fnfe);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public synchronized boolean testCloseTimeout() {
|
||||
/*
|
||||
if (System.currentTimeMillis() - TIMEOUT_TIME > lastAccessTime) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized DataOutputStream getOutputStream(int x, int z) {
|
||||
int index = getChunkIndex(x, z);
|
||||
return new DataOutputStream(new DeflaterOutputStream(new McMMOSimpleChunkBuffer(this, index)));
|
||||
}
|
||||
|
||||
public synchronized DataInputStream getInputStream(int x, int z) throws IOException {
|
||||
int index = getChunkIndex(x, z);
|
||||
int actualLength = dataActualLength[index];
|
||||
|
||||
if (actualLength == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] data = new byte[actualLength];
|
||||
|
||||
getFile().seek(dataStart[index] << segmentSize);
|
||||
getFile().readFully(data);
|
||||
return new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)));
|
||||
}
|
||||
|
||||
synchronized void write(int index, byte[] buffer, int size) throws IOException {
|
||||
int oldStart = setInUse(index, false);
|
||||
int start = findSpace(oldStart, size);
|
||||
getFile().seek(start << segmentSize);
|
||||
getFile().write(buffer, 0, size);
|
||||
dataStart[index] = start;
|
||||
dataActualLength[index] = size;
|
||||
dataLength[index] = sizeToSegments(size);
|
||||
setInUse(index, true);
|
||||
saveFAT();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
try {
|
||||
if (file != null) {
|
||||
file.seek(4096 * 2);
|
||||
file.close();
|
||||
}
|
||||
|
||||
file = null;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException("Unable to close file", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int setInUse(int index, boolean used) {
|
||||
if (dataActualLength[index] == 0) {
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
int start = dataStart[index];
|
||||
int end = start + dataLength[index];
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
while (i > inuse.size() - 1) {
|
||||
inuse.add(false);
|
||||
}
|
||||
|
||||
Boolean old = inuse.set(i, used);
|
||||
if (old != null && old == used) {
|
||||
if (old) {
|
||||
throw new IllegalStateException("Attempting to overwrite an in-use segment");
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Attempting to delete empty segment");
|
||||
}
|
||||
}
|
||||
|
||||
return dataStart[index];
|
||||
}
|
||||
|
||||
private synchronized void extendFile() throws IOException {
|
||||
long extend = (-getFile().length()) & segmentMask;
|
||||
|
||||
getFile().seek(getFile().length());
|
||||
|
||||
while ((extend--) > 0) {
|
||||
getFile().write(0);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int findSpace(int oldStart, int size) {
|
||||
int segments = sizeToSegments(size);
|
||||
|
||||
boolean oldFree = true;
|
||||
for (int i = oldStart; i < inuse.size() && i < oldStart + segments; i++) {
|
||||
if (inuse.get(i)) {
|
||||
oldFree = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldFree) {
|
||||
return oldStart;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
|
||||
while (end < inuse.size()) {
|
||||
if (inuse.get(end)) {
|
||||
end++;
|
||||
start = end;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
|
||||
if (end - start >= segments) {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
private synchronized int sizeToSegments(int size) {
|
||||
if (size <= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ((size - 1) >> segmentSize) + 1;
|
||||
}
|
||||
|
||||
private synchronized Integer getChunkIndex(int x, int z) {
|
||||
if (rx != (x >> 5) || rz != (z >> 5)) {
|
||||
throw new RuntimeException(x + ", " + z + " not in region " + rx + ", " + rz);
|
||||
}
|
||||
|
||||
x = x & 0x1F;
|
||||
z = z & 0x1F;
|
||||
|
||||
return (x << 5) + z;
|
||||
}
|
||||
|
||||
private synchronized void saveFAT() throws IOException {
|
||||
getFile().seek(0);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataStart[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
getFile().writeInt(dataActualLength[i]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.block.Block;
|
||||
import com.gmail.nossr50.core.mcmmo.block.BlockState;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Entity;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NullChunkManager implements ChunkManager {
|
||||
|
||||
@Override
|
||||
public void closeAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkStore readChunkStore(World world, int x, int z) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChunkStore(World world, int x, int z, ChunkStore data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeChunkStore(World world, int x, int z) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunklet(int cx, int cy, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunklet(int cx, int cy, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChunk(int cx, int cz, World world, Entity[] entities) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadChunk(int cx, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChunk(int cx, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int cx, int cz, World world) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkLoaded(int cx, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chunkUnloaded(int cx, int cz, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveWorld(World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadAll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z, World world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(Block block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(BlockState blockState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(Block block) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(BlockState blockState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z, World world) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(Block block) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(BlockState blockState) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.chunkmeta;
|
||||
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PrimitiveChunkStore implements ChunkStore {
|
||||
private static final long serialVersionUID = -1L;
|
||||
private static final int CURRENT_VERSION = 7;
|
||||
private static final int MAGIC_NUMBER = 0xEA5EDEBB;
|
||||
/**
|
||||
* X, Z, Y
|
||||
*/
|
||||
public boolean[][][] store;
|
||||
transient private boolean dirty = false;
|
||||
private int cx;
|
||||
private int cz;
|
||||
private UUID worldUid;
|
||||
|
||||
public PrimitiveChunkStore(World world, int cx, int cz) {
|
||||
this.cx = cx;
|
||||
this.cz = cz;
|
||||
this.worldUid = world.getUUID();
|
||||
this.store = new boolean[16][16][world.getMaxHeight()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty(boolean dirty) {
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkX() {
|
||||
return cx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChunkZ() {
|
||||
return cz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTrue(int x, int y, int z) {
|
||||
return store[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrue(int x, int y, int z) {
|
||||
if (y >= store[0][0].length || y < 0)
|
||||
return;
|
||||
store[x][z][y] = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFalse(int x, int y, int z) {
|
||||
if (y >= store[0][0].length || y < 0)
|
||||
return;
|
||||
store[x][z][y] = false;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
if (store[x][z][y]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(ChunkletStore otherStore) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
store[x][z][y] = otherStore.isTrue(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
out.writeInt(MAGIC_NUMBER);
|
||||
out.writeInt(CURRENT_VERSION);
|
||||
|
||||
out.writeLong(worldUid.getLeastSignificantBits());
|
||||
out.writeLong(worldUid.getMostSignificantBits());
|
||||
out.writeInt(cx);
|
||||
out.writeInt(cz);
|
||||
out.writeObject(store);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
int magic = in.readInt();
|
||||
// Can be used to determine the format of the file
|
||||
int fileVersionNumber = in.readInt();
|
||||
|
||||
if (magic != MAGIC_NUMBER) {
|
||||
fileVersionNumber = 0;
|
||||
}
|
||||
|
||||
long lsb = in.readLong();
|
||||
long msb = in.readLong();
|
||||
worldUid = new UUID(msb, lsb);
|
||||
cx = in.readInt();
|
||||
cz = in.readInt();
|
||||
|
||||
store = (boolean[][][]) in.readObject();
|
||||
|
||||
if (fileVersionNumber < 5) {
|
||||
fixArray();
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void fixArray() {
|
||||
boolean[][][] temp = this.store;
|
||||
this.store = new boolean[16][16][Bukkit.getWorld(worldUid).getMaxHeight()];
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < store[0][0].length; y++) {
|
||||
try {
|
||||
store[x][z][y] = temp[x][y][z];
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.config.ChunkConversionOptions;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionMain implements Runnable {
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] xDirs;
|
||||
BlockStoreConversionXDirectory[] converters;
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
|
||||
public BlockStoreConversionMain(org.bukkit.World world) {
|
||||
this.taskID = -1;
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.dataDir = new File(this.world.getWorldFolder(), "mcmmo_data");
|
||||
this.converters = new BlockStoreConversionXDirectory[ChunkConversionOptions.getInstance().getConversionRate()];
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
softStop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.xDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < ChunkConversionOptions.getInstance().getConversionRate()) && (this.i < this.xDirs.length); this.i++) {
|
||||
if (this.converters[this.i] == null) {
|
||||
this.converters[this.i] = new BlockStoreConversionXDirectory();
|
||||
}
|
||||
|
||||
this.converters[this.i].start(this.world, this.xDirs[this.i]);
|
||||
}
|
||||
|
||||
softStop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void softStop() {
|
||||
stop();
|
||||
|
||||
if (this.dataDir.exists() || this.dataDir.isDirectory()) {
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
mcMMO.p.getLogger().info("Finished converting the storage for " + world.getName() + ".");
|
||||
|
||||
this.dataDir = null;
|
||||
this.xDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.config.ChunkConversionOptions;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionXDirectory implements Runnable {
|
||||
BukkitScheduler scheduler;
|
||||
File dataDir;
|
||||
File[] zDirs;
|
||||
BlockStoreConversionZDirectory[] converters;
|
||||
private int taskID, i;
|
||||
private org.bukkit.World world;
|
||||
|
||||
public BlockStoreConversionXDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(org.bukkit.World world, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = mcMMO.p.getServer().getScheduler();
|
||||
this.converters = new BlockStoreConversionZDirectory[ChunkConversionOptions.getInstance().getConversionRate()];
|
||||
this.dataDir = dataDir;
|
||||
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.zDirs = this.dataDir.listFiles();
|
||||
|
||||
for (this.i = 0; (this.i < ChunkConversionOptions.getInstance().getConversionRate()) && (this.i < this.zDirs.length); this.i++) {
|
||||
if (this.converters[this.i] == null) {
|
||||
this.converters[this.i] = new BlockStoreConversionZDirectory();
|
||||
}
|
||||
|
||||
this.converters[this.i].start(this.world, this.dataDir, this.zDirs[this.i]);
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(this.taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.dataDir = null;
|
||||
this.zDirs = null;
|
||||
this.world = null;
|
||||
this.scheduler = null;
|
||||
this.converters = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
package com.gmail.nossr50.core.data.blockmeta.conversion;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.ChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.HashChunkletManager;
|
||||
import com.gmail.nossr50.core.data.blockmeta.PrimitiveChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.PrimitiveExChunkletStore;
|
||||
import com.gmail.nossr50.core.data.blockmeta.chunkmeta.HashChunkManager;
|
||||
import com.gmail.nossr50.core.data.blockmeta.chunkmeta.PrimitiveChunkStore;
|
||||
import com.gmail.nossr50.core.mcmmo.tasks.TaskScheduler;
|
||||
import com.gmail.nossr50.core.mcmmo.world.World;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class BlockStoreConversionZDirectory implements Runnable {
|
||||
public int taskID, cx, cz, x, y, z, y2, xPos, zPos, cxPos, czPos;
|
||||
private String cxs, czs, chunkletName, chunkName;
|
||||
private World world;
|
||||
//private BukkitScheduler scheduler;
|
||||
private TaskScheduler scheduler;
|
||||
private File xDir, dataDir;
|
||||
private HashChunkletManager manager;
|
||||
private HashChunkManager newManager;
|
||||
private ChunkletStore tempChunklet;
|
||||
private PrimitiveChunkletStore primitiveChunklet = null;
|
||||
private PrimitiveExChunkletStore primitiveExChunklet = null;
|
||||
private PrimitiveChunkStore currentChunk;
|
||||
private boolean[] oldArray, newArray;
|
||||
|
||||
public BlockStoreConversionZDirectory() {
|
||||
this.taskID = -1;
|
||||
}
|
||||
|
||||
public void start(World world, File xDir, File dataDir) {
|
||||
this.world = world;
|
||||
this.scheduler = McmmoCore.getTaskScheduler();
|
||||
this.manager = new HashChunkletManager();
|
||||
this.newManager = (HashChunkManager) mcMMO.getPlaceStore();
|
||||
this.dataDir = dataDir;
|
||||
this.xDir = xDir;
|
||||
|
||||
if (this.taskID >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bukkit - this.taskID = this.scheduler.runTaskLater(mcMMO.p, this, 1).getTaskId();
|
||||
this.taskID = scheduler.scheduleTask(this, 1).getTaskId();
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!this.dataDir.exists()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataDir.isDirectory()) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.dataDir.listFiles().length <= 0) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.cxs = this.xDir.getName();
|
||||
this.czs = this.dataDir.getName();
|
||||
this.cx = 0;
|
||||
this.cz = 0;
|
||||
|
||||
try {
|
||||
this.cx = Integer.parseInt(this.cxs);
|
||||
this.cz = Integer.parseInt(this.czs);
|
||||
} catch (Exception e) {
|
||||
this.dataDir.delete();
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.manager.loadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for (this.y = 0; this.y < (this.world.getMaxHeight() / 64); this.y++) {
|
||||
this.chunkletName = this.world.getName() + "," + this.cx + "," + this.cz + "," + this.y;
|
||||
this.tempChunklet = this.manager.store.get(this.chunkletName);
|
||||
|
||||
if (this.tempChunklet instanceof PrimitiveChunkletStore) {
|
||||
this.primitiveChunklet = (PrimitiveChunkletStore) this.tempChunklet;
|
||||
} else if (this.tempChunklet instanceof PrimitiveExChunkletStore) {
|
||||
this.primitiveExChunklet = (PrimitiveExChunkletStore) this.tempChunklet;
|
||||
}
|
||||
|
||||
if (this.tempChunklet == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.chunkName = this.world.getName() + "," + this.cx + "," + this.cz;
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
if (this.currentChunk != null) {
|
||||
this.xPos = this.cx * 16;
|
||||
this.zPos = this.cz * 16;
|
||||
|
||||
for (this.x = 0; this.x < 16; this.x++) {
|
||||
for (this.z = 0; this.z < 16; this.z++) {
|
||||
this.cxPos = this.xPos + this.x;
|
||||
this.czPos = this.zPos + this.z;
|
||||
|
||||
for (this.y2 = (64 * this.y); this.y2 < (64 * this.y + 64); this.y2++) {
|
||||
try {
|
||||
if (!this.manager.isTrue(this.cxPos, this.y2, this.czPos, this.world)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.newManager.setTrue(this.cxPos, this.y2, this.czPos, this.world);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.newManager.setTrue(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.newManager.setFalse(this.cx * 16, 0, this.cz * 16, this.world);
|
||||
this.currentChunk = (PrimitiveChunkStore) this.newManager.store.get(this.chunkName);
|
||||
|
||||
for (this.x = 0; this.x < 16; this.x++) {
|
||||
for (this.z = 0; this.z < 16; this.z++) {
|
||||
if (this.primitiveChunklet != null) {
|
||||
this.oldArray = this.primitiveChunklet.store[x][z];
|
||||
}
|
||||
|
||||
if (this.primitiveExChunklet != null) {
|
||||
this.oldArray = this.primitiveExChunklet.store[x][z];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.newArray = this.currentChunk.store[x][z];
|
||||
|
||||
if (this.oldArray.length < 64) {
|
||||
return;
|
||||
} else if (this.newArray.length < ((this.y * 64) + 64)) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.arraycopy(this.oldArray, 0, this.newArray, (this.y * 64), 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.manager.unloadChunk(this.cx, this.cz, this.world);
|
||||
this.newManager.unloadChunk(this.cx, this.cz, this.world);
|
||||
|
||||
for (File yFile : dataDir.listFiles()) {
|
||||
if (!yFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yFile.delete();
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.taskID < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduler.cancelTask(taskID);
|
||||
this.taskID = -1;
|
||||
|
||||
this.cxs = null;
|
||||
this.czs = null;
|
||||
this.chunkletName = null;
|
||||
this.chunkName = null;
|
||||
this.manager = null;
|
||||
this.xDir = null;
|
||||
this.dataDir = null;
|
||||
this.tempChunklet = null;
|
||||
this.primitiveChunklet = null;
|
||||
this.primitiveExChunklet = null;
|
||||
this.currentChunk = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package com.gmail.nossr50.core.data.database;
|
||||
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.datatypes.database.DatabaseType;
|
||||
import com.gmail.nossr50.core.datatypes.database.PlayerStat;
|
||||
import com.gmail.nossr50.core.datatypes.player.PlayerProfile;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface DatabaseManager {
|
||||
// One month in milliseconds
|
||||
public final long PURGE_TIME = 2630000000L * MainConfig.getInstance().getOldUsersCutoff();
|
||||
// During convertUsers, how often to output a status
|
||||
public final int progressInterval = 200;
|
||||
|
||||
/**
|
||||
* Purge users with 0 power level from the database.
|
||||
*/
|
||||
public void purgePowerlessUsers();
|
||||
|
||||
/**
|
||||
* Purge users who haven't logged on in over a certain time frame from the database.
|
||||
*/
|
||||
public void purgeOldUsers();
|
||||
|
||||
/**
|
||||
* Remove a user from the database.
|
||||
*
|
||||
* @param playerName The name of the user to remove
|
||||
* @return true if the user was successfully removed, false otherwise
|
||||
*/
|
||||
public boolean removeUser(String playerName);
|
||||
|
||||
/**
|
||||
* Save a user to the database.
|
||||
*
|
||||
* @param profile The profile of the player to save
|
||||
* @return true if successful, false on failure
|
||||
*/
|
||||
public boolean saveUser(PlayerProfile profile);
|
||||
|
||||
/**
|
||||
* Retrieve leaderboard info.
|
||||
*
|
||||
* @param skill The skill to retrieve info on
|
||||
* @param pageNumber Which page in the leaderboards to retrieve
|
||||
* @param statsPerPage The number of stats per page
|
||||
* @return the requested leaderboard information
|
||||
*/
|
||||
public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage);
|
||||
|
||||
/**
|
||||
* Retrieve rank info into a HashMap from PrimarySkillType to the rank.
|
||||
* <p>
|
||||
* The special value <code>null</code> is used to represent the Power
|
||||
* Level rank (the combination of all skill levels).
|
||||
*
|
||||
* @param playerName The name of the user to retrieve the rankings for
|
||||
* @return the requested rank information
|
||||
*/
|
||||
public Map<PrimarySkillType, Integer> readRank(String playerName);
|
||||
|
||||
/**
|
||||
* Add a new user to the database.
|
||||
*
|
||||
* @param playerName The name of the player to be added to the database
|
||||
* @param uuid The uuid of the player to be added to the database
|
||||
*/
|
||||
public void newUser(String playerName, UUID uuid);
|
||||
|
||||
/**
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @param playerName The name of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
* found
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
* and createNew is false
|
||||
* @deprecated replaced by {@link #loadPlayerProfile(String playerName, UUID uuid, boolean createNew)}
|
||||
*/
|
||||
@Deprecated
|
||||
public PlayerProfile loadPlayerProfile(String playerName, boolean createNew);
|
||||
|
||||
/**
|
||||
* Load a player from the database.
|
||||
*
|
||||
* @param uuid The uuid of the player to load from the database
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
*/
|
||||
public PlayerProfile loadPlayerProfile(UUID uuid);
|
||||
|
||||
/**
|
||||
* Load a player from the database. Attempt to use uuid, fall back on playername
|
||||
*
|
||||
* @param playerName The name of the player to load from the database
|
||||
* @param uuid The uuid of the player to load from the database
|
||||
* @param createNew Whether to create a new record if the player is not
|
||||
* found
|
||||
* @return The player's data, or an unloaded PlayerProfile if not found
|
||||
* and createNew is false
|
||||
*/
|
||||
public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean createNew);
|
||||
|
||||
/**
|
||||
* Get all users currently stored in the database.
|
||||
*
|
||||
* @return list of playernames
|
||||
*/
|
||||
public List<String> getStoredUsers();
|
||||
|
||||
/**
|
||||
* Convert all users from this database to the provided database using
|
||||
* {@link #saveUser(PlayerProfile)}.
|
||||
*
|
||||
* @param destination The DatabaseManager to save to
|
||||
*/
|
||||
public void convertUsers(DatabaseManager destination);
|
||||
|
||||
public boolean saveUserUUID(String userName, UUID uuid);
|
||||
|
||||
public boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs);
|
||||
|
||||
/**
|
||||
* Retrieve the type of database in use. Custom databases should return CUSTOM.
|
||||
*
|
||||
* @return The type of database
|
||||
*/
|
||||
public DatabaseType getDatabaseType();
|
||||
|
||||
/**
|
||||
* Called when the plugin disables
|
||||
*/
|
||||
public void onDisable();
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.gmail.nossr50.core.data.database;
|
||||
|
||||
import com.gmail.nossr50.config.Config;
|
||||
import com.gmail.nossr50.core.mcmmo.database.DatabaseType;
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
|
||||
public class DatabaseManagerFactory {
|
||||
private static Class<? extends DatabaseManager> customManager = null;
|
||||
|
||||
public static DatabaseManager getDatabaseManager() {
|
||||
if (customManager != null) {
|
||||
try {
|
||||
return createDefaultCustomDatabaseManager();
|
||||
} catch (Exception e) {
|
||||
mcMMO.p.debug("Could not create custom database manager");
|
||||
e.printStackTrace();
|
||||
} catch (Throwable e) {
|
||||
mcMMO.p.debug("Failed to create custom database manager");
|
||||
e.printStackTrace();
|
||||
}
|
||||
mcMMO.p.debug("Falling back on " + (Config.getInstance().getUseMySQL() ? "SQL" : "Flatfile") + " database");
|
||||
}
|
||||
|
||||
return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatfileDatabaseManager();
|
||||
}
|
||||
|
||||
public static Class<? extends DatabaseManager> getCustomDatabaseManagerClass() {
|
||||
return customManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom DatabaseManager class for mcMMO to use. This should be
|
||||
* called prior to mcMMO enabling.
|
||||
* <p/>
|
||||
* The provided class must have an empty constructor, which is the one
|
||||
* that will be used.
|
||||
* <p/>
|
||||
* This method is intended for API use, but it should not be considered
|
||||
* stable. This method is subject to change and/or removal in future
|
||||
* versions.
|
||||
*
|
||||
* @param clazz the DatabaseManager class to use
|
||||
* @throws IllegalArgumentException if the provided class does not have
|
||||
* an empty constructor
|
||||
*/
|
||||
public static void setCustomDatabaseManagerClass(Class<? extends DatabaseManager> clazz) {
|
||||
try {
|
||||
clazz.getConstructor();
|
||||
customManager = clazz;
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalArgumentException("Provided database manager class must have an empty constructor", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static DatabaseManager createDatabaseManager(DatabaseType type) {
|
||||
switch (type) {
|
||||
case DatabaseType.FLATFILE:
|
||||
return new FlatfileDatabaseManager();
|
||||
|
||||
case DatabaseType.SQL:
|
||||
return new SQLDatabaseManager();
|
||||
|
||||
case DatabaseType.CUSTOM:
|
||||
try {
|
||||
return createDefaultCustomDatabaseManager();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable {
|
||||
return customManager.getConstructor().newInstance();
|
||||
}
|
||||
|
||||
public static DatabaseManager createCustomDatabaseManager(Class<? extends DatabaseManager> clazz) throws Throwable {
|
||||
return clazz.getConstructor().newInstance();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,53 @@
|
||||
package com.gmail.nossr50.core.datatypes;
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.world.Location;
|
||||
|
||||
public class LimitedSizeList {
|
||||
private final int size;
|
||||
public Location[] limitedSizeOrderedList;
|
||||
|
||||
|
||||
public LimitedSizeList(int size) {
|
||||
this.size = size;
|
||||
limitedSizeOrderedList = new Location[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds objects to our limited size ordered list
|
||||
* New objects are added to the front
|
||||
*
|
||||
* @param newItem
|
||||
*/
|
||||
public void add(Location newItem) {
|
||||
Location[] newList = new Location[size];
|
||||
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
if (i != 0)
|
||||
newList[i] = limitedSizeOrderedList[i - 1];
|
||||
else
|
||||
newList[i] = newItem;
|
||||
}
|
||||
|
||||
limitedSizeOrderedList = newList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the object is anywhere in our list
|
||||
*
|
||||
* @param targetLoc the object to check for
|
||||
* @return true if the object is in our list
|
||||
*/
|
||||
public boolean contains(Location targetLoc) {
|
||||
for (Location iter : limitedSizeOrderedList) {
|
||||
if (iter == null)
|
||||
continue;
|
||||
|
||||
if (iter.getX() == targetLoc.getX()
|
||||
&& iter.getY() == targetLoc.getY()
|
||||
&& iter.getZ() == targetLoc.getZ())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.gmail.nossr50.core.datatypes.chat;
|
||||
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
|
||||
public enum ChatMode {
|
||||
ADMIN(LocaleLoader.getString("Commands.AdminChat.On"), LocaleLoader.getString("Commands.AdminChat.Off")),
|
||||
PARTY(LocaleLoader.getString("Commands.Party.Chat.On"), LocaleLoader.getString("Commands.Party.Chat.Off"));
|
||||
|
||||
private String enabledMessage;
|
||||
private String disabledMessage;
|
||||
|
||||
private ChatMode(String enabledMessage, String disabledMessage) {
|
||||
this.enabledMessage = enabledMessage;
|
||||
this.disabledMessage = disabledMessage;
|
||||
}
|
||||
|
||||
public String getEnabledMessage() {
|
||||
return enabledMessage;
|
||||
}
|
||||
|
||||
public String getDisabledMessage() {
|
||||
return disabledMessage;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.gmail.nossr50.core.datatypes.database;
|
||||
|
||||
public enum DatabaseType {
|
||||
FLATFILE,
|
||||
SQL,
|
||||
CUSTOM;
|
||||
|
||||
public static DatabaseType getDatabaseType(String typeName) {
|
||||
for (DatabaseType type : values()) {
|
||||
if (type.name().equalsIgnoreCase(typeName)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeName.equalsIgnoreCase("file")) {
|
||||
return FLATFILE;
|
||||
} else if (typeName.equalsIgnoreCase("mysql")) {
|
||||
return SQL;
|
||||
}
|
||||
|
||||
return CUSTOM;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.gmail.nossr50.core.datatypes.database;
|
||||
|
||||
public class PlayerStat {
|
||||
public String name;
|
||||
public int statVal = 0;
|
||||
|
||||
public PlayerStat(String name, int value) {
|
||||
this.name = name;
|
||||
this.statVal = value;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.gmail.nossr50.core.datatypes.database;
|
||||
|
||||
public enum UpgradeType {
|
||||
ADD_FISHING,
|
||||
ADD_BLAST_MINING_COOLDOWN,
|
||||
ADD_SQL_INDEXES,
|
||||
ADD_MOB_HEALTHBARS,
|
||||
DROP_SQL_PARTY_NAMES,
|
||||
DROP_SPOUT,
|
||||
ADD_ALCHEMY,
|
||||
ADD_UUIDS,
|
||||
ADD_UUIDS_PARTY,
|
||||
ADD_SCOREBOARD_TIPS,
|
||||
DROP_NAME_UNIQUENESS,
|
||||
ADD_SKILL_TOTAL,
|
||||
ADD_UNIQUE_PLAYER_DATA,
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.gmail.nossr50.core.datatypes.experience;
|
||||
|
||||
public enum FormulaType {
|
||||
LINEAR,
|
||||
EXPONENTIAL,
|
||||
UNKNOWN;
|
||||
|
||||
public static FormulaType getFormulaType(String string) {
|
||||
try {
|
||||
return valueOf(string);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.gmail.nossr50.core.datatypes.experience;
|
||||
|
||||
import com.gmail.nossr50.core.config.experience.ExperienceConfig;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SkillXpGain implements Delayed {
|
||||
private final long expiryTime;
|
||||
private final float xp;
|
||||
private final PrimarySkillType type;
|
||||
|
||||
public SkillXpGain(PrimarySkillType type, float xp) {
|
||||
this.expiryTime = System.currentTimeMillis() + getDuration();
|
||||
this.xp = xp;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private static long getDuration() {
|
||||
return TimeUnit.MINUTES.toMillis(ExperienceConfig.getInstance().getDiminishedReturnsTimeInterval());
|
||||
}
|
||||
|
||||
public PrimarySkillType getSkill() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public float getXp() {
|
||||
return xp;
|
||||
}
|
||||
|
||||
public int compareTo(SkillXpGain other) {
|
||||
if (this.expiryTime < other.expiryTime) {
|
||||
return -1;
|
||||
} else if (this.expiryTime > other.expiryTime) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed other) {
|
||||
if (other instanceof SkillXpGain) {
|
||||
// Use more efficient method if possible (private fields)
|
||||
return this.compareTo((SkillXpGain) other);
|
||||
}
|
||||
return (int) (getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit arg0) {
|
||||
return arg0.convert(expiryTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.gmail.nossr50.core.datatypes.experience;
|
||||
|
||||
public enum XPGainReason {
|
||||
PVP,
|
||||
PVE,
|
||||
VAMPIRISM,
|
||||
SHARED_PVP,
|
||||
SHARED_PVE,
|
||||
COMMAND,
|
||||
UNKNOWN;
|
||||
|
||||
public static XPGainReason getXPGainReason(String reason) {
|
||||
for (XPGainReason type : values()) {
|
||||
if (type.name().equalsIgnoreCase(reason)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.gmail.nossr50.core.datatypes.experience;
|
||||
|
||||
public enum XPGainSource {
|
||||
SELF,
|
||||
VAMPIRISM, //From Vampirism kills
|
||||
PASSIVE, //Smelting, Brewing, etc...
|
||||
PARTY_MEMBERS, //From other members of a party
|
||||
COMMAND,
|
||||
CUSTOM, //Outside Sources
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.gmail.nossr50.core.datatypes.interactions;
|
||||
|
||||
/**
|
||||
* This class helps define the types of information interactions we will have with players
|
||||
*/
|
||||
public enum NotificationType {
|
||||
XP_GAIN("ExperienceGain"),
|
||||
HARDCORE_MODE("HardcoreMode"),
|
||||
NO_PERMISSION("NoPermission"),
|
||||
SUBSKILL_UNLOCKED("SubSkillUnlocked"),
|
||||
LEVEL_UP_MESSAGE("LevelUps"),
|
||||
HOLIDAY("Holiday"),
|
||||
SUBSKILL_MESSAGE("SubSkillInteraction"),
|
||||
SUBSKILL_MESSAGE_FAILED("SubSkillFailed"),
|
||||
TOOL("ToolReady"),
|
||||
REQUIREMENTS_NOT_MET("RequirementsNotMet"),
|
||||
ABILITY_OFF("AbilityOff"),
|
||||
ABILITY_COOLDOWN("AbilityCoolDown"),
|
||||
ABILITY_REFRESHED("AbilityRefreshed"),
|
||||
SUPER_ABILITY("SuperAbilityInteraction"),
|
||||
SUPER_ABILITY_ALERT_OTHERS("SuperAbilityAlertOthers"),
|
||||
ITEM_MESSAGE("ItemMessage"),
|
||||
PARTY_MESSAGE("PartyMessage");
|
||||
|
||||
final String niceName;
|
||||
|
||||
NotificationType(String niceName) {
|
||||
this.niceName = niceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return niceName;
|
||||
}}
|
@ -0,0 +1,9 @@
|
||||
package com.gmail.nossr50.core.datatypes.json;
|
||||
|
||||
|
||||
public class CustomBaseComponent extends BaseComponent {
|
||||
@Override
|
||||
public BaseComponent duplicate() {
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.gmail.nossr50.core.datatypes.json;
|
||||
|
||||
public class McMMOUrl {
|
||||
public static final String urlWebsite = "https://www.mcmmo.org";
|
||||
public static final String urlDiscord = "https://discord.gg/bJ7pFS9";
|
||||
public static final String urlPatreon = "https://www.patreon.com/com.gmail.nossr50";
|
||||
public static final String urlWiki = "https://www.mcmmo.org/wiki/";
|
||||
public static final String urlSpigot = "http://spigot.mcmmo.org";
|
||||
public static final String urlTranslate = "https://www.mcmmo.org/translate/";
|
||||
|
||||
public static String getUrl(McMMOWebLinks webLinks) {
|
||||
switch (webLinks) {
|
||||
case WIKI:
|
||||
return urlWiki;
|
||||
case PATREON:
|
||||
return urlPatreon;
|
||||
case SPIGOT:
|
||||
return urlSpigot;
|
||||
case DISCORD:
|
||||
return urlDiscord;
|
||||
case WEBSITE:
|
||||
return urlWebsite;
|
||||
case HELP_TRANSLATE:
|
||||
return urlTranslate;
|
||||
default:
|
||||
return "https://www.mcmmo.org";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.gmail.nossr50.core.datatypes.json;
|
||||
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
public enum McMMOWebLinks {
|
||||
WEBSITE,
|
||||
DISCORD,
|
||||
PATREON,
|
||||
SPIGOT,
|
||||
HELP_TRANSLATE,
|
||||
WIKI;
|
||||
|
||||
public String getUrl() {
|
||||
return McMMOUrl.getUrl(this);
|
||||
}
|
||||
|
||||
public String getNiceTitle() {
|
||||
return StringUtils.getCapitalized(toString());
|
||||
}
|
||||
|
||||
public String getLocaleDescription() {
|
||||
switch (this) {
|
||||
case WEBSITE:
|
||||
return LocaleLoader.getString("JSON.URL.Website");
|
||||
case DISCORD:
|
||||
return LocaleLoader.getString("JSON.URL.Discord");
|
||||
case PATREON:
|
||||
return LocaleLoader.getString("JSON.URL.Patreon");
|
||||
case HELP_TRANSLATE:
|
||||
return LocaleLoader.getString("JSON.URL.Translation");
|
||||
case SPIGOT:
|
||||
return LocaleLoader.getString("JSON.URL.Spigot");
|
||||
case WIKI:
|
||||
return LocaleLoader.getString("JSON.URL.Wiki");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.gmail.nossr50.core.datatypes.meta;
|
||||
|
||||
|
||||
/**
|
||||
* This class is for storing mob names since we switch them to heart values
|
||||
*/
|
||||
public class OldName extends FixedMetadataValue {
|
||||
|
||||
public OldName(String oldName, mcMMO plugin) {
|
||||
super(plugin, oldName);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.gmail.nossr50.core.datatypes.mods;
|
||||
|
||||
public class CustomBlock {
|
||||
private int xpGain;
|
||||
private boolean canDoubleDrop;
|
||||
private int smeltingXpGain;
|
||||
|
||||
public CustomBlock(int xpGain, boolean canDoubleDrop, int smeltingXpGain) {
|
||||
this.xpGain = xpGain;
|
||||
this.canDoubleDrop = canDoubleDrop;
|
||||
this.smeltingXpGain = smeltingXpGain;
|
||||
}
|
||||
|
||||
public int getXpGain() {
|
||||
return xpGain;
|
||||
}
|
||||
|
||||
public boolean isDoubleDropEnabled() {
|
||||
return canDoubleDrop;
|
||||
}
|
||||
|
||||
public int getSmeltingXpGain() {
|
||||
return smeltingXpGain;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.gmail.nossr50.core.datatypes.mods;
|
||||
|
||||
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
|
||||
public class CustomEntity {
|
||||
private double xpMultiplier;
|
||||
private boolean canBeTamed;
|
||||
private int tamingXP;
|
||||
private boolean canBeSummoned;
|
||||
private ItemStack callOfTheWildItem;
|
||||
private int callOfTheWildAmount;
|
||||
|
||||
public CustomEntity(double xpMultiplier, boolean canBeTamed, int tamingXP, boolean canBeSummoned, ItemStack callOfTheWildItem, int callOfTheWildAmount) {
|
||||
this.xpMultiplier = xpMultiplier;
|
||||
this.canBeTamed = canBeTamed;
|
||||
this.tamingXP = tamingXP;
|
||||
this.canBeSummoned = canBeSummoned;
|
||||
this.callOfTheWildItem = callOfTheWildItem;
|
||||
this.callOfTheWildAmount = callOfTheWildAmount;
|
||||
}
|
||||
|
||||
public double getXpMultiplier() {
|
||||
return xpMultiplier;
|
||||
}
|
||||
|
||||
public boolean canBeTamed() {
|
||||
return canBeTamed;
|
||||
}
|
||||
|
||||
public int getTamingXP() {
|
||||
return tamingXP;
|
||||
}
|
||||
|
||||
public boolean canBeSummoned() {
|
||||
return canBeSummoned;
|
||||
}
|
||||
|
||||
public ItemStack getCallOfTheWildItem() {
|
||||
return callOfTheWildItem;
|
||||
}
|
||||
|
||||
public int getCallOfTheWildAmount() {
|
||||
return callOfTheWildAmount;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.gmail.nossr50.core.datatypes.mods;
|
||||
|
||||
public class CustomTool {
|
||||
private double xpMultiplier;
|
||||
private boolean abilityEnabled;
|
||||
private int tier;
|
||||
|
||||
public CustomTool(int tier, boolean abilityEnabled, double xpMultiplier) {
|
||||
this.xpMultiplier = xpMultiplier;
|
||||
this.abilityEnabled = abilityEnabled;
|
||||
this.tier = tier;
|
||||
}
|
||||
|
||||
public double getXpMultiplier() {
|
||||
return xpMultiplier;
|
||||
}
|
||||
|
||||
public boolean isAbilityEnabled() {
|
||||
return abilityEnabled;
|
||||
}
|
||||
|
||||
public int getTier() {
|
||||
return tier;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.util.ItemUtils;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
public enum ItemShareType {
|
||||
LOOT,
|
||||
MINING,
|
||||
HERBALISM,
|
||||
WOODCUTTING,
|
||||
MISC;
|
||||
|
||||
public static ItemShareType getShareType(ItemStack itemStack) {
|
||||
if (ItemUtils.isMobDrop(itemStack)) {
|
||||
return LOOT;
|
||||
} else if (ItemUtils.isMiningDrop(itemStack)) {
|
||||
return MINING;
|
||||
} else if (ItemUtils.isHerbalismDrop(itemStack)) {
|
||||
return HERBALISM;
|
||||
} else if (ItemUtils.isWoodcuttingDrop(itemStack)) {
|
||||
return WOODCUTTING;
|
||||
} else if (ItemUtils.isMiscDrop(itemStack)) {
|
||||
return MISC;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getLocaleString() {
|
||||
return LocaleLoader.getString("Party.ItemShare.Category." + StringUtils.getCapitalized(this.toString()));
|
||||
}
|
||||
}
|
@ -0,0 +1,370 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.config.experience.ExperienceConfig;
|
||||
import com.gmail.nossr50.core.datatypes.experience.FormulaType;
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.mcmmo.colors.ChatColor;
|
||||
import com.gmail.nossr50.core.mcmmo.commands.CommandSender;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.party.PartyManager;
|
||||
import com.gmail.nossr50.core.util.EventUtils;
|
||||
import com.gmail.nossr50.core.util.sounds.SoundManager;
|
||||
import com.gmail.nossr50.core.util.sounds.SoundType;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Party {
|
||||
private final LinkedHashMap<UUID, String> members = new LinkedHashMap<UUID, String>();
|
||||
private final List<Player> onlineMembers = new ArrayList<Player>();
|
||||
|
||||
private PartyLeader leader;
|
||||
private String name;
|
||||
private String password;
|
||||
private boolean locked;
|
||||
private Party ally;
|
||||
private int level;
|
||||
private float xp;
|
||||
|
||||
private ShareMode xpShareMode = ShareMode.NONE;
|
||||
private ShareMode itemShareMode = ShareMode.NONE;
|
||||
|
||||
private boolean shareLootDrops = true;
|
||||
private boolean shareMiningDrops = true;
|
||||
private boolean shareHerbalismDrops = true;
|
||||
private boolean shareWoodcuttingDrops = true;
|
||||
private boolean shareMiscDrops = true;
|
||||
|
||||
public Party(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Party(PartyLeader leader, String name) {
|
||||
this.leader = leader;
|
||||
this.name = name;
|
||||
this.locked = true;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
public Party(PartyLeader leader, String name, String password) {
|
||||
this.leader = leader;
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.locked = true;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
public Party(PartyLeader leader, String name, String password, boolean locked) {
|
||||
this.leader = leader;
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
this.locked = locked;
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
public LinkedHashMap<UUID, String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public List<Player> getOnlineMembers() {
|
||||
return onlineMembers;
|
||||
}
|
||||
|
||||
public List<Player> getVisibleMembers(Player player) {
|
||||
ArrayList<Player> visibleMembers = new ArrayList<>();
|
||||
|
||||
for (Player p : onlineMembers) {
|
||||
if (player.canSee(p))
|
||||
visibleMembers.add(p);
|
||||
}
|
||||
|
||||
return visibleMembers;
|
||||
}
|
||||
|
||||
public List<String> getOnlinePlayerNames(CommandSender sender) {
|
||||
Player player = sender instanceof Player ? (Player) sender : null;
|
||||
List<String> onlinePlayerNames = new ArrayList<String>();
|
||||
|
||||
for (Player onlinePlayer : getOnlineMembers()) {
|
||||
if (player != null && player.canSee(onlinePlayer)) {
|
||||
onlinePlayerNames.add(onlinePlayer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return onlinePlayerNames;
|
||||
}
|
||||
|
||||
public boolean addOnlineMember(Player player) {
|
||||
return onlineMembers.add(player);
|
||||
}
|
||||
|
||||
public boolean removeOnlineMember(Player player) {
|
||||
return onlineMembers.remove(player);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public PartyLeader getLeader() {
|
||||
return leader;
|
||||
}
|
||||
|
||||
public void setLeader(PartyLeader leader) {
|
||||
this.leader = leader;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
public Party getAlly() {
|
||||
return ally;
|
||||
}
|
||||
|
||||
public void setAlly(Party ally) {
|
||||
this.ally = ally;
|
||||
}
|
||||
|
||||
public List<String> getItemShareCategories() {
|
||||
List<String> shareCategories = new ArrayList<String>();
|
||||
|
||||
for (ItemShareType shareType : ItemShareType.values()) {
|
||||
if (sharingDrops(shareType)) {
|
||||
shareCategories.add(shareType.getLocaleString());
|
||||
}
|
||||
}
|
||||
|
||||
return shareCategories;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public float getXp() {
|
||||
return xp;
|
||||
}
|
||||
|
||||
public void setXp(float xp) {
|
||||
this.xp = xp;
|
||||
}
|
||||
|
||||
public void addXp(float xp) {
|
||||
setXp(getXp() + xp);
|
||||
}
|
||||
|
||||
protected float levelUp() {
|
||||
float xpRemoved = getXpToLevel();
|
||||
|
||||
setLevel(getLevel() + 1);
|
||||
setXp(getXp() - xpRemoved);
|
||||
|
||||
return xpRemoved;
|
||||
}
|
||||
|
||||
public int getXpToLevel() {
|
||||
FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
|
||||
return (mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType)) * (getOnlineMembers().size() + MainConfig.getInstance().getPartyXpCurveMultiplier());
|
||||
}
|
||||
|
||||
public String getXpToLevelPercentage() {
|
||||
DecimalFormat percent = new DecimalFormat("##0.00%");
|
||||
return percent.format(this.getXp() / getXpToLevel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an experience gain
|
||||
*
|
||||
* @param xp Experience amount to add
|
||||
*/
|
||||
public void applyXpGain(float xp) {
|
||||
if (!EventUtils.handlePartyXpGainEvent(this, xp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getXp() < getXpToLevel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int levelsGained = 0;
|
||||
float xpRemoved = 0;
|
||||
|
||||
while (getXp() >= getXpToLevel()) {
|
||||
if (hasReachedLevelCap()) {
|
||||
setXp(0);
|
||||
return;
|
||||
}
|
||||
|
||||
xpRemoved += levelUp();
|
||||
levelsGained++;
|
||||
}
|
||||
|
||||
if (!EventUtils.handlePartyLevelChangeEvent(this, levelsGained, xpRemoved)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MainConfig.getInstance().getPartyInformAllMembers()) {
|
||||
Player leader = mcMMO.p.getServer().getPlayer(this.leader.getUniqueId());
|
||||
|
||||
if (leader != null) {
|
||||
leader.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, getLevel()));
|
||||
|
||||
if (MainConfig.getInstance().getLevelUpSoundsEnabled()) {
|
||||
SoundManager.sendSound(leader, leader.getLocation(), SoundType.LEVEL_UP);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PartyManager.informPartyMembersLevelUp(this, levelsGained, getLevel());
|
||||
}
|
||||
|
||||
public boolean hasReachedLevelCap() {
|
||||
return MainConfig.getInstance().getPartyLevelCap() < getLevel() + 1;
|
||||
}
|
||||
|
||||
public ShareMode getXpShareMode() {
|
||||
return xpShareMode;
|
||||
}
|
||||
|
||||
public void setXpShareMode(ShareMode xpShareMode) {
|
||||
this.xpShareMode = xpShareMode;
|
||||
}
|
||||
|
||||
public ShareMode getItemShareMode() {
|
||||
return itemShareMode;
|
||||
}
|
||||
|
||||
public void setItemShareMode(ShareMode itemShareMode) {
|
||||
this.itemShareMode = itemShareMode;
|
||||
}
|
||||
|
||||
public boolean sharingDrops(ItemShareType shareType) {
|
||||
switch (shareType) {
|
||||
case HERBALISM:
|
||||
return shareHerbalismDrops;
|
||||
|
||||
case LOOT:
|
||||
return shareLootDrops;
|
||||
|
||||
case MINING:
|
||||
return shareMiningDrops;
|
||||
|
||||
case MISC:
|
||||
return shareMiscDrops;
|
||||
|
||||
case WOODCUTTING:
|
||||
return shareWoodcuttingDrops;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSharingDrops(ItemShareType shareType, boolean enabled) {
|
||||
switch (shareType) {
|
||||
case HERBALISM:
|
||||
shareHerbalismDrops = enabled;
|
||||
break;
|
||||
|
||||
case LOOT:
|
||||
shareLootDrops = enabled;
|
||||
break;
|
||||
|
||||
case MINING:
|
||||
shareMiningDrops = enabled;
|
||||
break;
|
||||
|
||||
case MISC:
|
||||
shareMiscDrops = enabled;
|
||||
break;
|
||||
|
||||
case WOODCUTTING:
|
||||
shareWoodcuttingDrops = enabled;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasMember(String memberName) {
|
||||
return this.getMembers().values().contains(memberName);
|
||||
}
|
||||
|
||||
public boolean hasMember(UUID uuid) {
|
||||
return this.getMembers().keySet().contains(uuid);
|
||||
}
|
||||
|
||||
public String createMembersList(Player player) {
|
||||
StringBuilder memberList = new StringBuilder();
|
||||
|
||||
for (Player otherPlayer : this.getVisibleMembers(player)) {
|
||||
String memberName = otherPlayer.getName();
|
||||
|
||||
if (this.getLeader().getUniqueId().equals(otherPlayer.getUniqueId())) {
|
||||
memberList.append(ChatColor.GOLD);
|
||||
|
||||
if (otherPlayer == null) {
|
||||
memberName = memberName.substring(0, 1) + ChatColor.GRAY + ChatColor.ITALIC + "" + memberName.substring(1);
|
||||
}
|
||||
} else if (otherPlayer != null) {
|
||||
memberList.append(ChatColor.WHITE);
|
||||
} else {
|
||||
memberList.append(ChatColor.GRAY);
|
||||
}
|
||||
|
||||
if (player.getName().equalsIgnoreCase(otherPlayer.getName())) {
|
||||
memberList.append(ChatColor.ITALIC);
|
||||
}
|
||||
|
||||
memberList.append(memberName).append(ChatColor.RESET).append(" ");
|
||||
}
|
||||
|
||||
return memberList.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Party)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Party other = (Party) obj;
|
||||
|
||||
if ((this.getName() == null) || (other.getName() == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getName().equals(other.getName());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.util.Permissions;
|
||||
import com.gmail.nossr50.core.util.StringUtils;
|
||||
|
||||
public enum PartyFeature {
|
||||
CHAT,
|
||||
TELEPORT,
|
||||
ALLIANCE,
|
||||
ITEM_SHARE,
|
||||
XP_SHARE;
|
||||
|
||||
public String getLocaleString() {
|
||||
return LocaleLoader.getString("Party.Feature." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""));
|
||||
}
|
||||
|
||||
public String getFeatureLockedLocaleString() {
|
||||
return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), MainConfig.getInstance().getPartyFeatureUnlockLevel(this)));
|
||||
}
|
||||
|
||||
public boolean hasPermission(Player player) {
|
||||
PartySubcommandType partySubCommandType;
|
||||
switch (this) {
|
||||
case CHAT:
|
||||
partySubCommandType = PartySubcommandType.CHAT;
|
||||
break;
|
||||
case TELEPORT:
|
||||
partySubCommandType = PartySubcommandType.TELEPORT;
|
||||
break;
|
||||
case ALLIANCE:
|
||||
partySubCommandType = PartySubcommandType.ALLIANCE;
|
||||
break;
|
||||
case ITEM_SHARE:
|
||||
partySubCommandType = PartySubcommandType.ITEMSHARE;
|
||||
break;
|
||||
case XP_SHARE:
|
||||
partySubCommandType = PartySubcommandType.XPSHARE;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return Permissions.partySubcommand(player, partySubCommandType);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PartyLeader {
|
||||
private UUID uuid;
|
||||
private String playerName;
|
||||
|
||||
public PartyLeader(UUID uuid, String playerName) {
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
}
|
||||
|
||||
public UUID getUniqueId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.util.Misc;
|
||||
|
||||
public class PartyTeleportRecord {
|
||||
private Player requestor;
|
||||
private boolean enabled, confirmRequired;
|
||||
private int timeout, lastUse;
|
||||
|
||||
public PartyTeleportRecord() {
|
||||
requestor = null;
|
||||
enabled = true;
|
||||
confirmRequired = MainConfig.getInstance().getPTPCommandConfirmRequired();
|
||||
timeout = 0;
|
||||
lastUse = 0;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void toggleEnabled() {
|
||||
enabled = !enabled;
|
||||
}
|
||||
|
||||
public Player getRequestor() {
|
||||
return requestor;
|
||||
}
|
||||
|
||||
public void setRequestor(Player requestor) {
|
||||
this.requestor = requestor;
|
||||
}
|
||||
|
||||
public boolean hasRequest() {
|
||||
return (requestor != null);
|
||||
}
|
||||
|
||||
public void removeRequest() {
|
||||
requestor = null;
|
||||
}
|
||||
|
||||
public boolean isConfirmRequired() {
|
||||
return confirmRequired;
|
||||
}
|
||||
|
||||
public void toggleConfirmRequired() {
|
||||
confirmRequired = !confirmRequired;
|
||||
}
|
||||
|
||||
public int getLastUse() {
|
||||
return lastUse;
|
||||
}
|
||||
|
||||
public void actualizeLastUse() {
|
||||
lastUse = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void actualizeTimeout() {
|
||||
timeout = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.gmail.nossr50.core.datatypes.party;
|
||||
|
||||
|
||||
import com.gmail.nossr50.core.util.commands.CommandUtils;
|
||||
|
||||
public enum ShareMode {
|
||||
NONE,
|
||||
EQUAL,
|
||||
RANDOM;
|
||||
|
||||
public static ShareMode getShareMode(String string) {
|
||||
try {
|
||||
return valueOf(string);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
if (string.equalsIgnoreCase("even")) {
|
||||
return EQUAL;
|
||||
} else if (CommandUtils.shouldDisableToggle(string)) {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,995 @@
|
||||
package com.gmail.nossr50.core.datatypes.player;
|
||||
|
||||
import com.gmail.nossr50.core.McmmoCore;
|
||||
import com.gmail.nossr50.core.config.AdvancedConfig;
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.config.WorldBlacklist;
|
||||
import com.gmail.nossr50.core.config.experience.ExperienceConfig;
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.chat.ChatMode;
|
||||
import com.gmail.nossr50.core.datatypes.experience.XPGainReason;
|
||||
import com.gmail.nossr50.core.datatypes.experience.XPGainSource;
|
||||
import com.gmail.nossr50.core.datatypes.interactions.NotificationType;
|
||||
import com.gmail.nossr50.core.datatypes.mods.CustomTool;
|
||||
import com.gmail.nossr50.core.datatypes.party.Party;
|
||||
import com.gmail.nossr50.core.datatypes.party.PartyTeleportRecord;
|
||||
import com.gmail.nossr50.core.locale.LocaleLoader;
|
||||
import com.gmail.nossr50.core.mcmmo.entity.Player;
|
||||
import com.gmail.nossr50.core.mcmmo.item.ItemStack;
|
||||
import com.gmail.nossr50.core.mcmmo.meta.Metadata;
|
||||
import com.gmail.nossr50.core.mcmmo.meta.MetadataDefinitions;
|
||||
import com.gmail.nossr50.core.mcmmo.world.Location;
|
||||
import com.gmail.nossr50.core.party.PartyManager;
|
||||
import com.gmail.nossr50.core.party.ShareHandler;
|
||||
import com.gmail.nossr50.core.runnables.skills.AbilityDisableTask;
|
||||
import com.gmail.nossr50.core.runnables.skills.BleedTimerTask;
|
||||
import com.gmail.nossr50.core.runnables.skills.ToolLowerTask;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.skills.SkillManager;
|
||||
import com.gmail.nossr50.core.skills.SuperAbilityType;
|
||||
import com.gmail.nossr50.core.skills.ToolType;
|
||||
import com.gmail.nossr50.core.skills.child.FamilyTree;
|
||||
import com.gmail.nossr50.core.skills.child.salvage.SalvageManager;
|
||||
import com.gmail.nossr50.core.skills.child.smelting.SmeltingManager;
|
||||
import com.gmail.nossr50.core.skills.primary.acrobatics.AcrobaticsManager;
|
||||
import com.gmail.nossr50.core.skills.primary.alchemy.AlchemyManager;
|
||||
import com.gmail.nossr50.core.skills.primary.archery.ArcheryManager;
|
||||
import com.gmail.nossr50.core.skills.primary.axes.AxesManager;
|
||||
import com.gmail.nossr50.core.skills.primary.excavation.ExcavationManager;
|
||||
import com.gmail.nossr50.core.skills.primary.fishing.FishingManager;
|
||||
import com.gmail.nossr50.core.skills.primary.herbalism.HerbalismManager;
|
||||
import com.gmail.nossr50.core.skills.primary.mining.MiningManager;
|
||||
import com.gmail.nossr50.core.skills.primary.repair.RepairManager;
|
||||
import com.gmail.nossr50.core.skills.primary.swords.SwordsManager;
|
||||
import com.gmail.nossr50.core.skills.primary.taming.TamingManager;
|
||||
import com.gmail.nossr50.core.skills.primary.unarmed.UnarmedManager;
|
||||
import com.gmail.nossr50.core.skills.primary.woodcutting.WoodcuttingManager;
|
||||
import com.gmail.nossr50.core.util.EventUtils;
|
||||
import com.gmail.nossr50.core.util.Misc;
|
||||
import com.gmail.nossr50.core.util.Permissions;
|
||||
import com.gmail.nossr50.core.util.experience.ExperienceBarManager;
|
||||
import com.gmail.nossr50.core.util.player.NotificationManager;
|
||||
import com.gmail.nossr50.core.util.scoreboards.ScoreboardManager;
|
||||
import com.gmail.nossr50.core.util.skills.ParticleEffectUtils;
|
||||
import com.gmail.nossr50.core.util.skills.PerksUtils;
|
||||
import com.gmail.nossr50.core.util.skills.RankUtils;
|
||||
import com.gmail.nossr50.core.util.skills.SkillUtils;
|
||||
import com.gmail.nossr50.core.util.sounds.SoundManager;
|
||||
import com.gmail.nossr50.core.util.sounds.SoundType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class McMMOPlayer {
|
||||
private final Map<PrimarySkillType, SkillManager> skillManagers = new HashMap<PrimarySkillType, SkillManager>();
|
||||
private final Map<SuperAbilityType, Boolean> abilityMode = new HashMap<SuperAbilityType, Boolean>();
|
||||
private final Map<SuperAbilityType, Boolean> abilityInformed = new HashMap<SuperAbilityType, Boolean>();
|
||||
private final Map<ToolType, Boolean> toolMode = new HashMap<ToolType, Boolean>();
|
||||
private final Metadata playerMetadata;
|
||||
private Player player;
|
||||
private PlayerProfile profile;
|
||||
private ExperienceBarManager experienceBarManager;
|
||||
private Party party;
|
||||
private Party invite;
|
||||
private Party allianceInvite;
|
||||
private int itemShareModifier;
|
||||
private PartyTeleportRecord ptpRecord;
|
||||
private boolean partyChatMode;
|
||||
private boolean adminChatMode;
|
||||
private boolean displaySkillNotifications = true;
|
||||
private boolean abilityUse = true;
|
||||
private boolean godMode;
|
||||
private boolean chatSpy = false; //Off by default
|
||||
private int recentlyHurt;
|
||||
private int respawnATS;
|
||||
private int teleportATS;
|
||||
private long databaseATS;
|
||||
//private int chimeraWingLastUse;
|
||||
private Location teleportCommence;
|
||||
private boolean isUsingUnarmed;
|
||||
|
||||
public McMMOPlayer(Player player, PlayerProfile profile) {
|
||||
String playerName = player.getName();
|
||||
UUID uuid = player.getUUID();
|
||||
|
||||
this.player = player;
|
||||
playerMetadata = player.setMetadata(MetadataDefinitions.MCMMO_METADATA_PLAYERDATA_KEY, playerName); //new FixedMetadataValue(mcMMO.p, playerName);
|
||||
this.profile = profile;
|
||||
|
||||
if (profile.getUniqueId() == null) {
|
||||
profile.setUniqueId(uuid);
|
||||
}
|
||||
|
||||
/*
|
||||
* I'm using this method because it makes code shorter and safer (we don't have to add all SkillTypes manually),
|
||||
* but I actually have no idea about the performance impact, if there is any.
|
||||
* If in the future someone wants to remove this, don't forget to also remove what is in the PrimarySkillType enum. - bm01
|
||||
*/
|
||||
try {
|
||||
for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
|
||||
skillManagers.put(primarySkillType, primarySkillType.getManagerClass().getConstructor(McMMOPlayer.class).newInstance(this));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
McmmoCore.p.disablePlugin(); //Disable Plugin
|
||||
//mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
|
||||
}
|
||||
|
||||
for (SuperAbilityType superAbilityType : SuperAbilityType.values()) {
|
||||
abilityMode.put(superAbilityType, false);
|
||||
abilityInformed.put(superAbilityType, true); // This is intended
|
||||
}
|
||||
|
||||
for (ToolType toolType : ToolType.values()) {
|
||||
toolMode.put(toolType, false);
|
||||
}
|
||||
|
||||
experienceBarManager = new ExperienceBarManager(this);
|
||||
}
|
||||
|
||||
/*public void hideXpBar(PrimarySkillType primarySkillType)
|
||||
{
|
||||
experienceBarManager.hideExperienceBar(primarySkillType);
|
||||
}*/
|
||||
|
||||
public void processPostXpEvent(XPGainReason xpGainReason, PrimarySkillType primarySkillType, XPGainSource xpGainSource) {
|
||||
//Updates from Party sources
|
||||
if (xpGainSource == XPGainSource.PARTY_MEMBERS && !ExperienceConfig.getInstance().isPartyExperienceBarsEnabled())
|
||||
return;
|
||||
|
||||
//Updates from passive sources (Alchemy, Smelting, etc...)
|
||||
if (xpGainSource == XPGainSource.PASSIVE && !ExperienceConfig.getInstance().isPassiveGainsExperienceBarsEnabled())
|
||||
return;
|
||||
|
||||
updateXPBar(primarySkillType);
|
||||
}
|
||||
|
||||
public void processUnlockNotifications(PrimarySkillType primarySkillType, int skillLevel) {
|
||||
RankUtils.executeSkillUnlockNotifications(this, primarySkillType, skillLevel);
|
||||
}
|
||||
|
||||
public void updateXPBar(PrimarySkillType primarySkillType) {
|
||||
//Skill Unlock Notifications
|
||||
|
||||
if (primarySkillType.isChildSkill())
|
||||
return;
|
||||
|
||||
//XP BAR UPDATES
|
||||
experienceBarManager.updateExperienceBar(primarySkillType);
|
||||
}
|
||||
|
||||
public double getProgressInCurrentSkillLevel(PrimarySkillType primarySkillType) {
|
||||
double currentXP = profile.getSkillXpLevel(primarySkillType);
|
||||
double maxXP = profile.getXpToLevel(primarySkillType);
|
||||
|
||||
return (currentXP / maxXP);
|
||||
}
|
||||
|
||||
public AcrobaticsManager getAcrobaticsManager() {
|
||||
return (AcrobaticsManager) skillManagers.get(PrimarySkillType.ACROBATICS);
|
||||
}
|
||||
|
||||
public AlchemyManager getAlchemyManager() {
|
||||
return (AlchemyManager) skillManagers.get(PrimarySkillType.ALCHEMY);
|
||||
}
|
||||
|
||||
public ArcheryManager getArcheryManager() {
|
||||
return (ArcheryManager) skillManagers.get(PrimarySkillType.ARCHERY);
|
||||
}
|
||||
|
||||
public AxesManager getAxesManager() {
|
||||
return (AxesManager) skillManagers.get(PrimarySkillType.AXES);
|
||||
}
|
||||
|
||||
public ExcavationManager getExcavationManager() {
|
||||
return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION);
|
||||
}
|
||||
|
||||
public FishingManager getFishingManager() {
|
||||
return (FishingManager) skillManagers.get(PrimarySkillType.FISHING);
|
||||
}
|
||||
|
||||
public HerbalismManager getHerbalismManager() {
|
||||
return (HerbalismManager) skillManagers.get(PrimarySkillType.HERBALISM);
|
||||
}
|
||||
|
||||
public MiningManager getMiningManager() {
|
||||
return (MiningManager) skillManagers.get(PrimarySkillType.MINING);
|
||||
}
|
||||
|
||||
public RepairManager getRepairManager() {
|
||||
return (RepairManager) skillManagers.get(PrimarySkillType.REPAIR);
|
||||
}
|
||||
|
||||
public SalvageManager getSalvageManager() {
|
||||
return (SalvageManager) skillManagers.get(PrimarySkillType.SALVAGE);
|
||||
}
|
||||
|
||||
public SmeltingManager getSmeltingManager() {
|
||||
return (SmeltingManager) skillManagers.get(PrimarySkillType.SMELTING);
|
||||
}
|
||||
|
||||
public SwordsManager getSwordsManager() {
|
||||
return (SwordsManager) skillManagers.get(PrimarySkillType.SWORDS);
|
||||
}
|
||||
|
||||
public TamingManager getTamingManager() {
|
||||
return (TamingManager) skillManagers.get(PrimarySkillType.TAMING);
|
||||
}
|
||||
|
||||
public UnarmedManager getUnarmedManager() {
|
||||
return (UnarmedManager) skillManagers.get(PrimarySkillType.UNARMED);
|
||||
}
|
||||
|
||||
public WoodcuttingManager getWoodcuttingManager() {
|
||||
return (WoodcuttingManager) skillManagers.get(PrimarySkillType.WOODCUTTING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Abilities
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reset the mode of all abilities.
|
||||
*/
|
||||
public void resetAbilityMode() {
|
||||
for (SuperAbilityType ability : SuperAbilityType.values()) {
|
||||
// Correctly disable and handle any special deactivate code
|
||||
new AbilityDisableTask(this, ability).run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mode of an ability.
|
||||
*
|
||||
* @param ability The ability to check
|
||||
* @return true if the ability is enabled, false otherwise
|
||||
*/
|
||||
public boolean getAbilityMode(SuperAbilityType ability) {
|
||||
return abilityMode.get(ability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode of an ability.
|
||||
*
|
||||
* @param ability The ability to check
|
||||
* @param isActive True if the ability is active, false otherwise
|
||||
*/
|
||||
public void setAbilityMode(SuperAbilityType ability, boolean isActive) {
|
||||
abilityMode.put(ability, isActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the informed state of an ability
|
||||
*
|
||||
* @param ability The ability to check
|
||||
* @return true if the ability is informed, false otherwise
|
||||
*/
|
||||
public boolean getAbilityInformed(SuperAbilityType ability) {
|
||||
return abilityInformed.get(ability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the informed state of an ability.
|
||||
*
|
||||
* @param ability The ability to check
|
||||
* @param isInformed True if the ability is informed, false otherwise
|
||||
*/
|
||||
public void setAbilityInformed(SuperAbilityType ability, boolean isInformed) {
|
||||
abilityInformed.put(ability, isInformed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current prep mode of a tool.
|
||||
*
|
||||
* @param tool Tool to get the mode for
|
||||
* @return true if the tool is prepped, false otherwise
|
||||
*/
|
||||
public boolean getToolPreparationMode(ToolType tool) {
|
||||
return toolMode.get(tool);
|
||||
}
|
||||
|
||||
public boolean getAbilityUse() {
|
||||
return abilityUse;
|
||||
}
|
||||
|
||||
public void toggleAbilityUse() {
|
||||
abilityUse = !abilityUse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tools
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reset the prep modes of all tools.
|
||||
*/
|
||||
public void resetToolPrepMode() {
|
||||
for (ToolType tool : ToolType.values()) {
|
||||
setToolPreparationMode(tool, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current prep mode of a tool.
|
||||
*
|
||||
* @param tool Tool to set the mode for
|
||||
* @param isPrepared true if the tool should be prepped, false otherwise
|
||||
*/
|
||||
public void setToolPreparationMode(ToolType tool, boolean isPrepared) {
|
||||
toolMode.put(tool, isPrepared);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recently Hurt
|
||||
*/
|
||||
|
||||
public int getRecentlyHurt() {
|
||||
return recentlyHurt;
|
||||
}
|
||||
|
||||
public void setRecentlyHurt(int value) {
|
||||
recentlyHurt = value;
|
||||
}
|
||||
|
||||
public void actualizeRecentlyHurt() {
|
||||
recentlyHurt = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Teleportation cooldown & warmup
|
||||
*/
|
||||
|
||||
public int getChimeraWingLastUse() {
|
||||
return profile.getChimaerWingDATS();
|
||||
}
|
||||
|
||||
public void actualizeChimeraWingLastUse() {
|
||||
profile.setChimaeraWingDATS((int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR));
|
||||
}
|
||||
|
||||
public Location getTeleportCommenceLocation() {
|
||||
return teleportCommence;
|
||||
}
|
||||
|
||||
public void setTeleportCommenceLocation(Location location) {
|
||||
teleportCommence = location;
|
||||
}
|
||||
|
||||
public void actualizeTeleportCommenceLocation(Player player) {
|
||||
teleportCommence = player.getLocation();
|
||||
}
|
||||
|
||||
/*
|
||||
* Exploit Prevention
|
||||
*/
|
||||
|
||||
public int getRespawnATS() {
|
||||
return respawnATS;
|
||||
}
|
||||
|
||||
public void actualizeRespawnATS() {
|
||||
respawnATS = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
public int getTeleportATS() {
|
||||
return teleportATS;
|
||||
}
|
||||
|
||||
public void actualizeTeleportATS() {
|
||||
teleportATS = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
public long getDatabaseATS() {
|
||||
return databaseATS;
|
||||
}
|
||||
|
||||
public void actualizeDatabaseATS() {
|
||||
databaseATS = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/*
|
||||
* God Mode
|
||||
*/
|
||||
|
||||
public boolean getGodMode() {
|
||||
return godMode;
|
||||
}
|
||||
|
||||
public void toggleGodMode() {
|
||||
godMode = !godMode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Party Chat Spy
|
||||
*/
|
||||
|
||||
public boolean isPartyChatSpying() {
|
||||
return chatSpy;
|
||||
}
|
||||
|
||||
public void togglePartyChatSpying() {
|
||||
chatSpy = !chatSpy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skill notifications
|
||||
*/
|
||||
|
||||
public boolean useChatNotifications() {
|
||||
return displaySkillNotifications;
|
||||
}
|
||||
|
||||
public void toggleChatNotifications() {
|
||||
displaySkillNotifications = !displaySkillNotifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the power level of this player.
|
||||
*
|
||||
* @return the power level of the player
|
||||
*/
|
||||
public int getPowerLevel() {
|
||||
int powerLevel = 0;
|
||||
|
||||
for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) {
|
||||
if (type.getPermissions(player)) {
|
||||
powerLevel += getSkillLevel(type);
|
||||
}
|
||||
}
|
||||
|
||||
return powerLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins an experience gain. The amount will be affected by skill modifiers, global rate, perks, and may be shared with the party
|
||||
*
|
||||
* @param skill Skill being used
|
||||
* @param xp Experience amount to process
|
||||
*/
|
||||
public void beginXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) {
|
||||
Validate.isTrue(xp >= 0.0, "XP gained should be greater than or equal to zero.");
|
||||
|
||||
if (xp <= 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (skill.isChildSkill()) {
|
||||
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
|
||||
float splitXp = xp / parentSkills.size();
|
||||
|
||||
for (PrimarySkillType parentSkill : parentSkills) {
|
||||
if (parentSkill.getPermissions(player)) {
|
||||
beginXpGain(parentSkill, splitXp, xpGainReason, xpGainSource);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Return if the experience has been shared
|
||||
if (party != null && ShareHandler.handleXpShare(xp, this, skill, ShareHandler.getSharedXpGainReason(xpGainReason))) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginUnsharedXpGain(skill, xp, xpGainReason, xpGainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins an experience gain. The amount will be affected by skill modifiers, global rate and perks
|
||||
*
|
||||
* @param skill Skill being used
|
||||
* @param xp Experience amount to process
|
||||
*/
|
||||
public void beginUnsharedXpGain(PrimarySkillType skill, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) {
|
||||
applyXpGain(skill, modifyXpGain(skill, xp), xpGainReason, xpGainSource);
|
||||
|
||||
if (party == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MainConfig.getInstance().getPartyXpNearMembersNeeded() || !PartyManager.getNearMembers(this).isEmpty()) {
|
||||
party.applyXpGain(modifyXpGain(skill, xp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an experience gain
|
||||
*
|
||||
* @param primarySkillType Skill being used
|
||||
* @param xp Experience amount to add
|
||||
*/
|
||||
public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) {
|
||||
if (!primarySkillType.getPermissions(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (primarySkillType.isChildSkill()) {
|
||||
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(primarySkillType);
|
||||
|
||||
for (PrimarySkillType parentSkill : parentSkills) {
|
||||
applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventUtils.handleXpGainEvent(player, primarySkillType, xp, xpGainReason)) {
|
||||
return;
|
||||
}
|
||||
|
||||
isUsingUnarmed = (primarySkillType == PrimarySkillType.UNARMED);
|
||||
checkXp(primarySkillType, xpGainReason, xpGainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the XP of a skill.
|
||||
*
|
||||
* @param primarySkillType The skill to check
|
||||
*/
|
||||
private void checkXp(PrimarySkillType primarySkillType, XPGainReason xpGainReason, XPGainSource xpGainSource) {
|
||||
if (getSkillXpLevelRaw(primarySkillType) < getXpToLevel(primarySkillType)) {
|
||||
UserManager.getPlayer(player).processPostXpEvent(xpGainReason, primarySkillType, mcMMO.p, xpGainSource);
|
||||
return;
|
||||
}
|
||||
|
||||
int levelsGained = 0;
|
||||
float xpRemoved = 0;
|
||||
|
||||
while (getSkillXpLevelRaw(primarySkillType) >= getXpToLevel(primarySkillType)) {
|
||||
if (hasReachedLevelCap(primarySkillType)) {
|
||||
setSkillXpLevel(primarySkillType, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
xpRemoved += profile.levelUp(primarySkillType);
|
||||
levelsGained++;
|
||||
}
|
||||
|
||||
if (!EventUtils.handleLevelChangeEvent(player, primarySkillType, levelsGained, xpRemoved, true, xpGainReason)) {
|
||||
UserManager.getPlayer(player).processPostXpEvent(xpGainReason, primarySkillType, mcMMO.p, xpGainSource);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MainConfig.getInstance().getLevelUpSoundsEnabled()) {
|
||||
SoundManager.sendSound(player, player.getLocation(), SoundType.LEVEL_UP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the player unlocked any new skills
|
||||
*/
|
||||
|
||||
NotificationManager.sendPlayerLevelUpNotification(UserManager.getPlayer(player), primarySkillType, levelsGained, profile.getSkillLevel(primarySkillType));
|
||||
|
||||
//UPDATE XP BARS
|
||||
UserManager.getPlayer(player).processPostXpEvent(xpGainReason, primarySkillType, mcMMO.p, xpGainSource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Players & Profiles
|
||||
*/
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public PlayerProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Party Stuff
|
||||
*/
|
||||
|
||||
public void setupPartyData() {
|
||||
party = PartyManager.getPlayerParty(player.getName(), player.getUniqueId());
|
||||
ptpRecord = new PartyTeleportRecord();
|
||||
|
||||
if (inParty()) {
|
||||
loginParty();
|
||||
}
|
||||
}
|
||||
|
||||
public Party getPartyInvite() {
|
||||
return invite;
|
||||
}
|
||||
|
||||
public void setPartyInvite(Party invite) {
|
||||
this.invite = invite;
|
||||
}
|
||||
|
||||
public boolean hasPartyInvite() {
|
||||
return (invite != null);
|
||||
}
|
||||
|
||||
public Party getParty() {
|
||||
return party;
|
||||
}
|
||||
|
||||
public void setParty(Party party) {
|
||||
this.party = party;
|
||||
}
|
||||
|
||||
public boolean inParty() {
|
||||
return (party != null);
|
||||
}
|
||||
|
||||
public void removeParty() {
|
||||
party = null;
|
||||
}
|
||||
|
||||
public void removePartyInvite() {
|
||||
invite = null;
|
||||
}
|
||||
|
||||
public PartyTeleportRecord getPartyTeleportRecord() {
|
||||
return ptpRecord;
|
||||
}
|
||||
|
||||
public Party getPartyAllianceInvite() {
|
||||
return allianceInvite;
|
||||
}
|
||||
|
||||
public void setPartyAllianceInvite(Party allianceInvite) {
|
||||
this.allianceInvite = allianceInvite;
|
||||
}
|
||||
|
||||
public boolean hasPartyAllianceInvite() {
|
||||
return (allianceInvite != null);
|
||||
}
|
||||
|
||||
public void removePartyAllianceInvite() {
|
||||
allianceInvite = null;
|
||||
}
|
||||
|
||||
public void loginParty() {
|
||||
party.addOnlineMember(this.getPlayer());
|
||||
}
|
||||
|
||||
public int getItemShareModifier() {
|
||||
if (itemShareModifier < 10) {
|
||||
setItemShareModifier(10);
|
||||
}
|
||||
|
||||
return itemShareModifier;
|
||||
}
|
||||
|
||||
public void setItemShareModifier(int modifier) {
|
||||
itemShareModifier = Math.max(10, modifier);
|
||||
}
|
||||
|
||||
/*
|
||||
* Chat modes
|
||||
*/
|
||||
|
||||
public boolean isChatEnabled(ChatMode mode) {
|
||||
switch (mode) {
|
||||
case ADMIN:
|
||||
return adminChatMode;
|
||||
|
||||
case PARTY:
|
||||
return partyChatMode;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void disableChat(ChatMode mode) {
|
||||
switch (mode) {
|
||||
case ADMIN:
|
||||
adminChatMode = false;
|
||||
return;
|
||||
|
||||
case PARTY:
|
||||
partyChatMode = false;
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableChat(ChatMode mode) {
|
||||
switch (mode) {
|
||||
case ADMIN:
|
||||
adminChatMode = true;
|
||||
partyChatMode = false;
|
||||
return;
|
||||
|
||||
case PARTY:
|
||||
partyChatMode = true;
|
||||
adminChatMode = false;
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void toggleChat(ChatMode mode) {
|
||||
switch (mode) {
|
||||
case ADMIN:
|
||||
adminChatMode = !adminChatMode;
|
||||
partyChatMode = !adminChatMode && partyChatMode;
|
||||
return;
|
||||
|
||||
case PARTY:
|
||||
partyChatMode = !partyChatMode;
|
||||
adminChatMode = !partyChatMode && adminChatMode;
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUsingUnarmed() {
|
||||
return isUsingUnarmed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies an experience gain using skill modifiers, global rate and perks
|
||||
*
|
||||
* @param primarySkillType Skill being used
|
||||
* @param xp Experience amount to process
|
||||
* @return Modified experience
|
||||
*/
|
||||
private float modifyXpGain(PrimarySkillType primarySkillType, float xp) {
|
||||
if (player.getGameMode() == GameMode.CREATIVE || (primarySkillType.getMaxLevel() <= getSkillLevel(primarySkillType)) || (MainConfig.getInstance().getPowerLevelCap() <= getPowerLevel())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
xp = (float) (xp / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier());
|
||||
|
||||
if (MainConfig.getInstance().getToolModsEnabled()) {
|
||||
CustomTool tool = mcMMO.getModManager().getTool(player.getInventory().getItemInMainHand());
|
||||
|
||||
if (tool != null) {
|
||||
xp *= tool.getXpMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
return PerksUtils.handleXpPerks(player, xp, primarySkillType);
|
||||
}
|
||||
|
||||
public void checkGodMode() {
|
||||
if (godMode && !Permissions.mcgod(player)
|
||||
|| godMode && WorldBlacklist.isWorldBlacklisted(player.getWorld())) {
|
||||
toggleGodMode();
|
||||
player.sendMessage(LocaleLoader.getString("Commands.GodMode.Forbidden"));
|
||||
}
|
||||
}
|
||||
|
||||
public void checkParty() {
|
||||
if (inParty() && !Permissions.party(player)) {
|
||||
removeParty();
|
||||
player.sendMessage(LocaleLoader.getString("Party.Forbidden"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if an ability can be activated.
|
||||
*
|
||||
* @param skill The skill the ability is based on
|
||||
*/
|
||||
public void checkAbilityActivation(PrimarySkillType skill) {
|
||||
ToolType tool = skill.getTool();
|
||||
SuperAbilityType ability = skill.getAbility();
|
||||
|
||||
if (getAbilityMode(ability) || !ability.getPermissions(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//TODO: This is hacky and temporary solution until skills are move to the new system
|
||||
//Potential problems with this include skills with two super abilities (ie mining)
|
||||
if (!skill.isSuperAbilityUnlocked(getPlayer())) {
|
||||
int diff = RankUtils.getSuperAbilityUnlockRequirement(skill.getAbility()) - getSkillLevel(skill);
|
||||
|
||||
//Inform the player they are not yet skilled enough
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
int timeRemaining = calculateTimeRemaining(ability);
|
||||
|
||||
if (timeRemaining > 0) {
|
||||
/*
|
||||
* Axes and Woodcutting are odd because they share the same tool.
|
||||
* We show them the too tired message when they take action.
|
||||
*/
|
||||
if (skill == PrimarySkillType.WOODCUTTING || skill == PrimarySkillType.AXES) {
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
|
||||
//SoundManager.sendSound(player, player.getLocation(), SoundType.TIRED);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (EventUtils.callPlayerAbilityActivateEvent(player, skill).isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//These values change depending on whether or not the server is in retro mode
|
||||
int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength();
|
||||
int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap();
|
||||
|
||||
int ticks;
|
||||
|
||||
//Ability cap of 0 or below means no cap
|
||||
if (abilityLengthCap > 0) {
|
||||
ticks = PerksUtils.handleActivationPerks(player, 2 + (Math.min(abilityLengthCap, getSkillLevel(skill)) / abilityLengthVar), ability.getMaxLength());
|
||||
} else {
|
||||
ticks = PerksUtils.handleActivationPerks(player, 2 + (getSkillLevel(skill) / abilityLengthVar), ability.getMaxLength());
|
||||
}
|
||||
|
||||
// Notify people that ability has been activated
|
||||
ParticleEffectUtils.playAbilityEnabledEffect(player);
|
||||
|
||||
if (useChatNotifications()) {
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, ability.getAbilityOn());
|
||||
//player.sendMessage(ability.getAbilityOn());
|
||||
}
|
||||
|
||||
SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayer());
|
||||
|
||||
//Sounds
|
||||
SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC);
|
||||
|
||||
|
||||
// Enable the ability
|
||||
profile.setAbilityDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR));
|
||||
setAbilityMode(ability, true);
|
||||
|
||||
if (ability == SuperAbilityType.SUPER_BREAKER || ability == SuperAbilityType.GIGA_DRILL_BREAKER) {
|
||||
SkillUtils.handleAbilitySpeedIncrease(player);
|
||||
}
|
||||
|
||||
setToolPreparationMode(tool, false);
|
||||
new AbilityDisableTask(this, ability).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
public void processAbilityActivation(PrimarySkillType skill) {
|
||||
if (MainConfig.getInstance().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack inHand = player.getInventory().getItemInMainHand();
|
||||
|
||||
if (mcMMO.getModManager().isCustomTool(inHand) && !mcMMO.getModManager().getTool(inHand).isAbilityEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getAbilityUse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (SuperAbilityType superAbilityType : SuperAbilityType.values()) {
|
||||
if (getAbilityMode(superAbilityType)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SuperAbilityType ability = skill.getAbility();
|
||||
ToolType tool = skill.getTool();
|
||||
|
||||
/*
|
||||
* Woodcutting & Axes need to be treated differently.
|
||||
* Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action
|
||||
*/
|
||||
if (tool.inHand(inHand) && !getToolPreparationMode(tool)) {
|
||||
if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) {
|
||||
int timeRemaining = calculateTimeRemaining(ability);
|
||||
|
||||
if (!getAbilityMode(ability) && timeRemaining > 0) {
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (MainConfig.getInstance().getAbilityMessagesEnabled()) {
|
||||
NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, tool.getRaiseTool());
|
||||
SoundManager.sendSound(player, player.getLocation(), SoundType.TOOL_READY);
|
||||
}
|
||||
|
||||
setToolPreparationMode(tool, true);
|
||||
new ToolLowerTask(this, tool).runTaskLaterAsynchronously(mcMMO.p, 4 * Misc.TICK_CONVERSION_FACTOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the time remaining until the ability's cooldown expires.
|
||||
*
|
||||
* @param ability SuperAbilityType whose cooldown to check
|
||||
* @return the number of seconds remaining before the cooldown expires
|
||||
*/
|
||||
public int calculateTimeRemaining(SuperAbilityType ability) {
|
||||
long deactivatedTimestamp = profile.getAbilityDATS(ability) * Misc.TIME_CONVERSION_FACTOR;
|
||||
return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR);
|
||||
}
|
||||
|
||||
private boolean hasReachedLevelCap(PrimarySkillType skill) {
|
||||
return (skill.getMaxLevel() < getSkillLevel(skill) + 1) || (MainConfig.getInstance().getPowerLevelCap() < getPowerLevel() + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions are wrapped from PlayerProfile so that we don't always have to store it alongside the McMMOPlayer object.
|
||||
*/
|
||||
public int getSkillLevel(PrimarySkillType skill) {
|
||||
return profile.getSkillLevel(skill);
|
||||
}
|
||||
|
||||
public float getSkillXpLevelRaw(PrimarySkillType skill) {
|
||||
return profile.getSkillXpLevelRaw(skill);
|
||||
}
|
||||
|
||||
public int getSkillXpLevel(PrimarySkillType skill) {
|
||||
return profile.getSkillXpLevel(skill);
|
||||
}
|
||||
|
||||
public void setSkillXpLevel(PrimarySkillType skill, float xpLevel) {
|
||||
profile.setSkillXpLevel(skill, xpLevel);
|
||||
}
|
||||
|
||||
public int getXpToLevel(PrimarySkillType skill) {
|
||||
return profile.getXpToLevel(skill);
|
||||
}
|
||||
|
||||
public void removeXp(PrimarySkillType skill, int xp) {
|
||||
profile.removeXp(skill, xp);
|
||||
}
|
||||
|
||||
public void modifySkill(PrimarySkillType skill, int level) {
|
||||
profile.modifySkill(skill, level);
|
||||
}
|
||||
|
||||
public void addLevels(PrimarySkillType skill, int levels) {
|
||||
profile.addLevels(skill, levels);
|
||||
}
|
||||
|
||||
public void addXp(PrimarySkillType skill, float xp) {
|
||||
profile.addXp(skill, xp);
|
||||
}
|
||||
|
||||
public void setAbilityDATS(SuperAbilityType ability, long DATS) {
|
||||
profile.setAbilityDATS(ability, DATS);
|
||||
}
|
||||
|
||||
public void resetCooldowns() {
|
||||
profile.resetCooldowns();
|
||||
}
|
||||
|
||||
public FixedMetadataValue getPlayerMetadata() {
|
||||
return playerMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by PlayerQuitEvent to tear down the mcMMOPlayer.
|
||||
*
|
||||
* @param syncSave if true, data is saved synchronously
|
||||
*/
|
||||
public void logout(boolean syncSave) {
|
||||
Player thisPlayer = getPlayer();
|
||||
resetAbilityMode();
|
||||
BleedTimerTask.bleedOut(thisPlayer);
|
||||
|
||||
if (syncSave) {
|
||||
getProfile().save();
|
||||
} else {
|
||||
getProfile().scheduleAsyncSave();
|
||||
}
|
||||
|
||||
UserManager.remove(thisPlayer);
|
||||
|
||||
if (MainConfig.getInstance().getScoreboardsEnabled())
|
||||
ScoreboardManager.teardownPlayer(thisPlayer);
|
||||
|
||||
if (inParty()) {
|
||||
party.removeOnlineMember(thisPlayer);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,385 @@
|
||||
package com.gmail.nossr50.core.datatypes.player;
|
||||
|
||||
import com.gmail.nossr50.core.config.AdvancedConfig;
|
||||
import com.gmail.nossr50.core.config.MainConfig;
|
||||
import com.gmail.nossr50.core.config.experience.ExperienceConfig;
|
||||
import com.gmail.nossr50.core.data.UserManager;
|
||||
import com.gmail.nossr50.core.datatypes.experience.FormulaType;
|
||||
import com.gmail.nossr50.core.datatypes.experience.SkillXpGain;
|
||||
import com.gmail.nossr50.core.runnables.player.PlayerProfileSaveTask;
|
||||
import com.gmail.nossr50.core.skills.MobHealthbarType;
|
||||
import com.gmail.nossr50.core.skills.PrimarySkillType;
|
||||
import com.gmail.nossr50.core.skills.SuperAbilityType;
|
||||
import com.gmail.nossr50.core.skills.child.FamilyTree;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.DelayQueue;
|
||||
|
||||
public class PlayerProfile {
|
||||
private final String playerName;
|
||||
/* Skill Data */
|
||||
private final Map<PrimarySkillType, Integer> skills = new HashMap<PrimarySkillType, Integer>(); // Skill & Level
|
||||
private final Map<PrimarySkillType, Float> skillsXp = new HashMap<PrimarySkillType, Float>(); // Skill & XP
|
||||
private final Map<SuperAbilityType, Integer> abilityDATS = new HashMap<SuperAbilityType, Integer>(); // Ability & Cooldown
|
||||
private final Map<UniqueDataType, Integer> uniquePlayerData = new HashMap<>(); //Misc data that doesn't fit into other categories (chimaera wing, etc..)
|
||||
private UUID uuid;
|
||||
private boolean loaded;
|
||||
private volatile boolean changed;
|
||||
/* HUDs */
|
||||
private MobHealthbarType mobHealthbarType;
|
||||
private int scoreboardTipsShown;
|
||||
// Store previous XP gains for deminished returns
|
||||
private DelayQueue<SkillXpGain> gainedSkillsXp = new DelayQueue<SkillXpGain>();
|
||||
private HashMap<PrimarySkillType, Float> rollingSkillsXp = new HashMap<PrimarySkillType, Float>();
|
||||
|
||||
@Deprecated
|
||||
public PlayerProfile(String playerName) {
|
||||
this(playerName, null);
|
||||
}
|
||||
|
||||
public PlayerProfile(String playerName, UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
this.playerName = playerName;
|
||||
|
||||
mobHealthbarType = MainConfig.getInstance().getMobHealthbarDefault();
|
||||
scoreboardTipsShown = 0;
|
||||
|
||||
for (SuperAbilityType superAbilityType : SuperAbilityType.values()) {
|
||||
abilityDATS.put(superAbilityType, 0);
|
||||
}
|
||||
|
||||
for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
|
||||
skills.put(primarySkillType, AdvancedConfig.getInstance().getStartingLevel());
|
||||
skillsXp.put(primarySkillType, 0F);
|
||||
}
|
||||
|
||||
//Misc Cooldowns
|
||||
uniquePlayerData.put(UniqueDataType.CHIMAERA_WING_DATS, 0); //Chimaera wing
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PlayerProfile(String playerName, boolean isLoaded) {
|
||||
this(playerName);
|
||||
this.loaded = isLoaded;
|
||||
}
|
||||
|
||||
public PlayerProfile(String playerName, UUID uuid, boolean isLoaded) {
|
||||
this(playerName, uuid);
|
||||
this.loaded = isLoaded;
|
||||
}
|
||||
|
||||
public PlayerProfile(String playerName, UUID uuid, Map<PrimarySkillType, Integer> levelData, Map<PrimarySkillType, Float> xpData, Map<SuperAbilityType, Integer> cooldownData, MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map<UniqueDataType, Integer> uniqueProfileData) {
|
||||
this.playerName = playerName;
|
||||
this.uuid = uuid;
|
||||
this.mobHealthbarType = mobHealthbarType;
|
||||
this.scoreboardTipsShown = scoreboardTipsShown;
|
||||
|
||||
skills.putAll(levelData);
|
||||
skillsXp.putAll(xpData);
|
||||
abilityDATS.putAll(cooldownData);
|
||||
uniquePlayerData.putAll(uniqueProfileData);
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
public void scheduleAsyncSave() {
|
||||
new PlayerProfileSaveTask(this).runTaskAsynchronously(mcMMO.p);
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (!changed || !loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO should this part be synchronized?
|
||||
PlayerProfile profileCopy = new PlayerProfile(playerName, uuid, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), mobHealthbarType, scoreboardTipsShown, ImmutableMap.copyOf(uniquePlayerData));
|
||||
changed = !mcMMO.getDatabaseManager().saveUser(profileCopy);
|
||||
|
||||
if (changed) {
|
||||
mcMMO.p.getLogger().warning("PlayerProfile saving failed for player: " + playerName + " " + uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
public UUID getUniqueId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUniqueId(UUID uuid) {
|
||||
changed = true;
|
||||
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mob Healthbars
|
||||
*/
|
||||
|
||||
public MobHealthbarType getMobHealthbarType() {
|
||||
return mobHealthbarType;
|
||||
}
|
||||
|
||||
public void setMobHealthbarType(MobHealthbarType mobHealthbarType) {
|
||||
changed = true;
|
||||
|
||||
this.mobHealthbarType = mobHealthbarType;
|
||||
}
|
||||
|
||||
public int getScoreboardTipsShown() {
|
||||
return scoreboardTipsShown;
|
||||
}
|
||||
|
||||
public void setScoreboardTipsShown(int scoreboardTipsShown) {
|
||||
changed = true;
|
||||
|
||||
this.scoreboardTipsShown = scoreboardTipsShown;
|
||||
}
|
||||
|
||||
public void increaseTipsShown() {
|
||||
setScoreboardTipsShown(getScoreboardTipsShown() + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cooldowns
|
||||
*/
|
||||
|
||||
public int getChimaerWingDATS() {
|
||||
return uniquePlayerData.get(UniqueDataType.CHIMAERA_WING_DATS);
|
||||
}
|
||||
|
||||
protected void setChimaeraWingDATS(int DATS) {
|
||||
changed = true;
|
||||
uniquePlayerData.put(UniqueDataType.CHIMAERA_WING_DATS, DATS);
|
||||
}
|
||||
|
||||
public void setUniqueData(UniqueDataType uniqueDataType, int newData) {
|
||||
changed = true;
|
||||
uniquePlayerData.put(uniqueDataType, newData);
|
||||
}
|
||||
|
||||
public long getUniqueData(UniqueDataType uniqueDataType) {
|
||||
return uniquePlayerData.get(uniqueDataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current deactivation timestamp of an ability.
|
||||
*
|
||||
* @param ability The {@link SuperAbilityType} to get the DATS for
|
||||
* @return the deactivation timestamp for the ability
|
||||
*/
|
||||
public long getAbilityDATS(SuperAbilityType ability) {
|
||||
return abilityDATS.get(ability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current deactivation timestamp of an ability.
|
||||
*
|
||||
* @param ability The {@link SuperAbilityType} to set the DATS for
|
||||
* @param DATS the DATS of the ability
|
||||
*/
|
||||
protected void setAbilityDATS(SuperAbilityType ability, long DATS) {
|
||||
changed = true;
|
||||
|
||||
abilityDATS.put(ability, (int) (DATS * .001D));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all ability cooldowns.
|
||||
*/
|
||||
protected void resetCooldowns() {
|
||||
changed = true;
|
||||
|
||||
for (SuperAbilityType ability : abilityDATS.keySet()) {
|
||||
abilityDATS.put(ability, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Xp Functions
|
||||
*/
|
||||
|
||||
public int getSkillLevel(PrimarySkillType skill) {
|
||||
return skill.isChildSkill() ? getChildSkillLevel(skill) : skills.get(skill);
|
||||
}
|
||||
|
||||
public float getSkillXpLevelRaw(PrimarySkillType skill) {
|
||||
return skillsXp.get(skill);
|
||||
}
|
||||
|
||||
public int getSkillXpLevel(PrimarySkillType skill) {
|
||||
return (int) Math.floor(getSkillXpLevelRaw(skill));
|
||||
}
|
||||
|
||||
public void setSkillXpLevel(PrimarySkillType skill, float xpLevel) {
|
||||
if (skill.isChildSkill()) {
|
||||
return;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
|
||||
skillsXp.put(skill, xpLevel);
|
||||
}
|
||||
|
||||
protected float levelUp(PrimarySkillType skill) {
|
||||
float xpRemoved = getXpToLevel(skill);
|
||||
|
||||
changed = true;
|
||||
|
||||
skills.put(skill, skills.get(skill) + 1);
|
||||
skillsXp.put(skill, skillsXp.get(skill) - xpRemoved);
|
||||
|
||||
return xpRemoved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Xp from a skill.
|
||||
*
|
||||
* @param skill Type of skill to modify
|
||||
* @param xp Amount of xp to remove
|
||||
*/
|
||||
public void removeXp(PrimarySkillType skill, int xp) {
|
||||
if (skill.isChildSkill()) {
|
||||
return;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
|
||||
skillsXp.put(skill, skillsXp.get(skill) - xp);
|
||||
}
|
||||
|
||||
public void removeXp(PrimarySkillType skill, float xp) {
|
||||
if (skill.isChildSkill()) {
|
||||
return;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
|
||||
skillsXp.put(skill, skillsXp.get(skill) - xp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a skill level.
|
||||
*
|
||||
* @param skill Type of skill to modify
|
||||
* @param level New level value for the skill
|
||||
*/
|
||||
public void modifySkill(PrimarySkillType skill, int level) {
|
||||
if (skill.isChildSkill()) {
|
||||
return;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
|
||||
//Don't allow levels to be negative
|
||||
if (level < 0)
|
||||
level = 0;
|
||||
|
||||
skills.put(skill, level);
|
||||
skillsXp.put(skill, 0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add levels to a skill.
|
||||
*
|
||||
* @param skill Type of skill to add levels to
|
||||
* @param levels Number of levels to add
|
||||
*/
|
||||
public void addLevels(PrimarySkillType skill, int levels) {
|
||||
modifySkill(skill, skills.get(skill) + levels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Experience to a skill.
|
||||
*
|
||||
* @param skill Type of skill to add experience to
|
||||
* @param xp Number of experience to add
|
||||
*/
|
||||
public void addXp(PrimarySkillType skill, float xp) {
|
||||
changed = true;
|
||||
|
||||
if (skill.isChildSkill()) {
|
||||
Set<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
|
||||
float dividedXP = (xp / parentSkills.size());
|
||||
|
||||
for (PrimarySkillType parentSkill : parentSkills) {
|
||||
skillsXp.put(parentSkill, skillsXp.get(parentSkill) + dividedXP);
|
||||
}
|
||||
} else {
|
||||
skillsXp.put(skill, skillsXp.get(skill) + xp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registered amount of experience gained
|
||||
* This is used for diminished XP returns
|
||||
*
|
||||
* @return xp Experience amount registered
|
||||
*/
|
||||
public float getRegisteredXpGain(PrimarySkillType primarySkillType) {
|
||||
float xp = 0F;
|
||||
|
||||
if (rollingSkillsXp.get(primarySkillType) != null) {
|
||||
xp = rollingSkillsXp.get(primarySkillType);
|
||||
}
|
||||
|
||||
return xp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an experience gain
|
||||
* This is used for diminished XP returns
|
||||
*
|
||||
* @param primarySkillType Skill being used
|
||||
* @param xp Experience amount to add
|
||||
*/
|
||||
public void registerXpGain(PrimarySkillType primarySkillType, float xp) {
|
||||
gainedSkillsXp.add(new SkillXpGain(primarySkillType, xp));
|
||||
rollingSkillsXp.put(primarySkillType, getRegisteredXpGain(primarySkillType) + xp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove experience gains older than a given time
|
||||
* This is used for diminished XP returns
|
||||
*/
|
||||
public void purgeExpiredXpGains() {
|
||||
SkillXpGain gain;
|
||||
while ((gain = gainedSkillsXp.poll()) != null) {
|
||||
rollingSkillsXp.put(gain.getSkill(), getRegisteredXpGain(gain.getSkill()) - gain.getXp());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of Xp remaining before the next level.
|
||||
*
|
||||
* @param primarySkillType Type of skill to check
|
||||
* @return the total amount of Xp until next level
|
||||
*/
|
||||
public int getXpToLevel(PrimarySkillType primarySkillType) {
|
||||
int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType);
|
||||
FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
|
||||
|
||||
return mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType);
|
||||
}
|
||||
|
||||
private int getChildSkillLevel(PrimarySkillType primarySkillType) {
|
||||
Set<PrimarySkillType> parents = FamilyTree.getParents(primarySkillType);
|
||||
int sum = 0;
|
||||
|
||||
for (PrimarySkillType parent : parents) {
|
||||
sum += Math.min(getSkillLevel(parent), parent.getMaxLevel());
|
||||
}
|
||||
|
||||
return sum / parents.size();
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.gmail.nossr50.core.datatypes.player;
|
||||
|
||||
public enum UniqueDataType {
|
||||
CHIMAERA_WING_DATS
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user